vector - Clojure HashMap 作为广义向量

标签 vector clojure hashmap linear-algebra addition

我想使用Clojure哈希图来定义广义 vector 。在此图片中,哈希图{:x 3:y 2:z(-3)}表示符号表达式3x + 2y-3z。

我想要一个函数gen +,它充当哈希图的加法运算,并且满足以下约束:

  • 将gen +应用于具有重叠键的两个哈希图将返回哈希值与这些键值之和。例如
  • (gen+ {:x 1} {:x 2});= {:x 3}
  • 将gen +应用于具有不同键的两个哈希图将返回结合了这些键值的哈希图。例如
  • (gen+ {:x 1} {:y 2});= {:x 1 :y 2}
  • 空的哈希图{}是gen +函数的加法标识。例如
  • (gen+ {:x 1} {}):= {:x 1}
  • 根据以上约束,任何条目为零的哈希图也是加性标识。例如,{:z 0}。由于存在这种冗余,gen +函数应始终返回没有任何0值的哈希图。例如
  • (gen+ {:x 1 :y 0} {:z 0});= {:x 1}
  • Clojure将丢失的键解释为具有值nil而不是({:x 3} :y) ;= nil,而不是0。因此,gen +应该以与0相同的方式对待nil值,例如
  • (gen+ {:x 1 :y 0} {:x nil :y nil}){:x 1}
  • 我的问题:我们如何编写满足以上约束的gen +函数?一旦到位,是否可以使gen +函数重载+运算符,从而实现哈希图的基本加法?


  • 显而易见的是,为什么这种形式主义将哈希图视为广义 vector 。 Clojure解释类似于[x0 x1 x2]之类的 vector ,与哈希图{:0 x0:1 x1:2 x2}几乎相同,只是略有不同,我不太了解。因此,如果我们将gen +应用于两个 vector ,则它实际上应与应用于它们的+相同。这使我们能够轻松处理稀疏 vector ,以及添加不同大小的 vector 。例如。,
    (gen+ [0 0 0 4] [0 0 0 0 0 0 0 0 0 9]);= {:4 4 :9 9}
    这是我对哈希图和 vector 不了解的内容。如果我将hashmap称为函数,则需要应用诸如:2之类的key参数。另一方面,如果我将 vector 称为函数,则需要应用索引参数,例如2。例如,
    ({:2 2} :2);= 2([0 1 2] 2];= 2
    即使您无法使用gen +函数,也可以解释一下为什么将hashmap和vector称为函数时行为不同?

    最佳答案

    这将首先删除nil0值,然后按照M Smith的建议添加带有merge-with的 map :

    (defn filter-vals
      [pred m]
      (into {} (filter (fn [[k v]] (pred v))
                       m)))
    
    (defn gen+
      [m1 m2]
      (letfn [(keep-val? [val]
                (and (not (nil? val))
                     (not (zero? val))))]
        (merge-with +
                    (filter-vals keep-val? m1)
                    (filter-vals keep-val? m2))))
    

    开始添加之前,您需要过滤掉所有nil,否则最终将尝试向数字添加nil,这是一个错误。但是,我概述的gen+可能返回带有0值的条目(请考虑(gen+ {:x 1} {:x -1}))。

    如果有可能根据您的输入,并且需要避免这种情况,则需要在合并后添加另一个过滤器:
    (defn gen+
      [m1 m2]
      (letfn [(keep-val? [val]
                (and (not (nil? val))
                     (not (zero? val))))]
        (->> (merge-with +
                         (filter-vals keep-val? m1)
                         (filter-vals keep-val? m2))
             (filter-vals keep-val?))))
    

    最后,这是一个可以处理可变数量的输入映射的版本:
    (defn gen+
      [& maps]
      (letfn [(keep-val? [val]
                (and (not (nil? val))
                     (not (zero? val))))]
        (->> (apply merge-with
                    +
                    (map #(filter-vals keep-val? %) maps))
             (filter-vals keep-val?))))
    

    因此,例如:
    (gen+ {:x 1} {:x 3} {:x 4 :y 5}) ;=> {:x 8, :y 5}
    

    关于映射和 vector 之间的区别,请这样考虑:映射是从键到值的函数,而 vector 是从索引到值的函数。在这两种情况下,如果都有一个“键”(一个 vector 是索引),则可以使用它来查找关联的值。

    我同意您到目前为止就重载clojure.core/+所获得的答案和评论(我不推荐);也就是说,这是一种解决方法,但有很多警告:
    (ns overload.example
      (:refer-clojure :exclude [+])
      (:require [clojure.core :as clj]))
    
    (in-ns 'overload.example)
    
    (defn gen+ ...)
    
    (defn + [& xs]
      (if (every? number? xs)
        (reduce clj/+ 0 xs)
        (apply gen+ xs)))
    

    关于vector - Clojure HashMap 作为广义向量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19669917/

    相关文章:

    vector - CUDA推力库: How can I create a host_vector of host_vectors of integers?

    clojure - 类似于Clojure对plists的get-in和assoc-in的操作

    flutter - 打印出所有hashMap值

    java - 将元素快速加载到具有固定索引的数组/列表中而不会重复

    c++ - 如何在不复制的情况下从 N 维容器中获取可迭代范围?

    c++ - 如何将模板化 vector 传递给 C++ 函数?

    c++ - 删除非指针 vector 中的指针

    javascript - 如何在 ClojureScript 中使用方法和构造函数创建 JS 对象

    clojure - Clojure 中 pmap 的更好替代方案,用于在大数据上并行化适度廉价的函数?

    java - 为什么java中的HashMap内部使用数组来存储Entry对象而不是ArrayList?