Clojure:遍历集合的映射 [英] Clojure: iterate over map of sets

查看:147
本文介绍了Clojure:遍历集合的映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这几乎是我最后一个问题的后续工作( Clojure惯用的方式来更新地图的多个值),但不完全一样。 (请记住,我对Clojure和函数式语言都很新)



假设我有以下数据结构,定义为集合映射:

 (def m1 {:1#{2}:2#{1 3}:3#{1}})

以及地图的地图:

 (def m2 {:1 {:10:2 12:3 23}:2 {:1 23:2 0:3 4}:3 {:1 2:2 4:3 0} } 

我想要做的是更新 m2 ,它们在m1中与某个值具有对应关系。假设我想要的值是 x m2 会是这样:

  {:1 { :10:2 x:3 23}:2 {:1 x:2 0:3 x}:3 {:1 x:2 4:3 0}} 
pre>

假设 v 包含我的地图的每一个可能的键,首次尝试,是这样做的:(假设 x = 1

  (for [iv] 
reduce(fn [mj](assoc-in m [ij] 1))d(i m1)))

不用说这是一个失败。

解决方案

根据我的理解你的要求


  1. m1 生成多个键序列。

  2. m2 将每个键序列与特定的常数值相关联。

第一步是对 m1 进行相当简单的转换。我们想为每个条目产生 0个或更多key-seqs (取决于它的集合中有多少个),所以对我来说自然的转换是 mapcat 。它代表 map -then - concat 并且是伟大的只是这样的情况下,从每个元素seq我们产生0个或更多我们想要的元素。

 (defn key-seqs [coll] 
(mapcat
(fn [[kv]]
(map(partial vector k)v))
coll))

(key-seqs m1)
;; = ([:1 2] [:2 1] [:2 3] [:3 1])$ ​​b $ b

注意, mapcat 采用的函数本身是一个 map ,所以它产生一个(可能为空) mapcat 以展开。但这是返回存储在集合中的渴望本身。如果我们想把它们变成关键字匹配 m2 ,我们需要一些更多的处理:

 (defn key-seqs [coll] 
(mapcat
(fn [[kv]]
b $ b coll))

(key-seqs m1)
;; => ([:1:2] [:2:1] [:2:3] [:3:1])$ ​​b $ b

(我们需要使用 str ,因为关键字不知道如何处理longs。关键字不是数字,而是具有某种符号含义的名称)



然后我们可以调整 update-m 上一个问题,以便它可以将常量值作为参数,并处理不只是具有相同的值两次的键序列:

 (defn update-m [mxv] 
(reduce(fn [m'key-seq]
(assoc-in m'key-seq x));; accumulate changes
m ;; initial-value
v));;收集到循环

,现在我们似乎在业务:

 (update-m m2 1(key-seqs m1))
;; => {:1 {:1 0,:2 1,:3 23},:2 {:11,:2 0,:3 1},:3 {:11,:2 4, b $ b


This is pretty much a follow-up to my last question (Clojure idiomatic way to update multiple values of map), but not quite the same. (keep in mind that I'm fairly new to Clojure and functional languages alike)

suppose I have the following data structure, defined as a map of sets:

(def m1 {:1 #{2} :2 #{1 3} :3 #{1}})

and a map of maps as such:

(def m2 {:1 {:1 0 :2 12 :3 23} :2 {:1 23 :2 0 :3 4} :3 {:1 2 :2 4 :3 0}})

What I want to do is update the registries of m2 that have a correspondence in m1 to a certain value. Let's say the value I want is x. The resulting m2 would be something like this:

{:1 {:1 0 :2 x :3 23} :2 {:1 x :2 0 :3 x} :3 {:1 x :2 4 :3 0}}

Assuming that v contains every possible key for my map, y first attempt, (that I failed miserably) is to do something like this: (assume that x=1

(for [i v]
 reduce (fn [m j] (assoc-in m [i j] 1)) d (i m1)))

needless to say that it was a failure. So, how is the idiomatic way to do this?

解决方案

As I understand your requirements you want to

  1. Produce a number of key-sequences from m1.
  2. In m2 associate each of those key-sequences with a particular constant value.

The first step is a fairly simple transformation of m1. We want to produce 0 or more key-seqs for each entry (depending on how many are in its set), so the natural go-to for me is mapcat. It stands for map-then-concat and is great for just such a case where from each element of a seq we produce 0 or more of the elements we want.

(defn key-seqs [coll]
  (mapcat 
   (fn [[k v]] 
     (map (partial vector k) v))
   coll))

(key-seqs m1)
;;=> ([:1 2] [:2 1] [:2 3] [:3 1])

Note that the function taken by mapcat is itself a map, so that it produces a sequence (possibly empty) for mapcat to unroll. But this is returning the longs stored in the sets as themselves. If we want to turn them into keywords to match m2 we need a little more processing:

(defn key-seqs [coll]
  (mapcat 
   (fn [[k v]] 
     (map (comp (partial vector k) keyword str) v))
   coll))

(key-seqs m1)
;;=> ([:1 :2] [:2 :1] [:2 :3] [:3 :1])

(We need to use str because keyword doesn't know what to do with longs. Normally keywords are not numbers, but names with some symbolic meaning)

Then we can adapt the update-m from your previous question a little bit so that it can take the constant value as an argument and handle key-sequences that don't just have the same value twice:

(defn update-m [m x v]
  (reduce (fn [m' key-seq]
            (assoc-in m' key-seq x)) ;; accumulate changes
          m   ;; initial-value
          v)) ;; collection to loop over

and now we seem to be in business:

(update-m m2 1 (key-seqs m1))
;;=> {:1 {:1 0, :2 1, :3 23}, :2 {:1 1, :2 0, :3 1}, :3 {:1 1, :2 4, :3 0}}

这篇关于Clojure:遍历集合的映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆