在哈希映射中对每个值进行映射

11

我有一个哈希表。 我想遍历所有值并根据值的类型替换每个值。如果该值是整数,则将其替换为true,否则用false替换。我希望这将返回一个新的哈希表,其中每个值都更新为true或false。

(defn my-function [hash-map]
  (loop [hash-map hash-map]
    (for [value (vals hash-map)]
      (if (= Integer (type value))
        (recur (assoc hash-map key true))
        (recur (assoc hash-map key false))))))

那样行不通,因为Clojure只能从尾部位置递归,但那是我想要做的一般性思路。有什么有效的方法吗?if-letupdate-in似乎是潜在的解决方案,但我无法完全理解它们。


1
我已经重新标记了问题,以描述问题的性质,而不是实现解决方案的一种可能方式。这样可以吗? - Matt Fenwick
4个回答

18
(reduce-kv (fn [m k v] (assoc m k (= Integer (type v)))) {} m)

如果您更喜欢的话,甚至可以更短:

(reduce-kv #(assoc %1 %2 (= Integer (type %3))) {} m)

为了保持地图的类型(散列 vs 排序):

(reduce-kv #(assoc %1 %2 (= Integer (type %3))) (empty m) m)

注意:最后一个无法与记录一起使用。


5
您提出的操作——独立地转换映射中的每个值——实际上已经在函子模块中实现。
要使用它,您需要实现可以转换单个值的函数,然后将其fmap到您的映射中:
(fmap your-function your-map)
< p > < em >(不要被fmap的名称误导 - 这个操作并不特定于映射。由于它是一个通用函数,它可以处理任何具有Functor实例的东西,这也包括列表、集合和向量)。 这是一个保持结构的操作:没有键会被更改,也不会添加新键,也不会删除任何键。

如果您希望避免使用通用函数,只需查看实现

(defmethod fmap clojure.lang.IPersistentMap
  [f m]
  (into (empty m) (for [[k v] m] [k (f v)])))  ;;; <== the important part!!

其中 f = 您的函数m = 您的映射表


这个库已经被移动到 clojure.algo.generic.functor。请参见 this 获取更多信息,以及 this 获取源代码。

这很简单,引入函数对象会相当奇怪。 - Rayne
@Rayne 不确定你的评论的意图是什么,因为我说“如果你更喜欢避免使用通用函数…”。 - Matt Fenwick
我的评论的意思仅仅是想指出,为这个特定的任务引入函数对象没什么意义。我并不是有意冒犯你。请不要对此太在意! - Rayne
@Rayne,我不确定在帖子中重复提到某事的意义是什么。 - Matt Fenwick
1
@MattFenwick 你知道 fmap 现在在哪个 ns 吗? - murtaza52
1
@murtaza52 哇,我很惊讶它移动了。看起来它现在可能在 clojure.algo.generic.functor 中。 - Matt Fenwick

3
(letfn [(map-vals [m f]
          (into {} (for [[k v] m]
                     [k (f v)])))]
  (map-vals m #(= Integer (type %))))

0
(defn f [m]
  (reduce (fn [res [k v]] 
            (assoc res k (= Integer (type v)))) 
          {} m))

或者如果你需要递归版本

(defn f 
  ([m] (f {} m))
  ([res m] (if (empty? m)
             res
             (let [[k v] (first m)]
               (recur (assoc res k (= Integer (type v))) 
                      (rest m))))))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接