在Clojure中将向量映射转换为列向量

在Clojure中将向量映射转换为列向量,clojure,Clojure,我有一个地图集合(或列表、序列或向量),如下所示: { :name "Bob", :data [32 11 180] } { :name "Joe", :data [ 4 8 30] } { :name "Sue", :data [10 9 40] } 我想创建新的向量,其中包含与描述数据的键相关联的向量“列”中的数据,如下所示: { :ages [32 4 10], :shoe-sizes [11 8 9], :weights [180 30 40] } 实际上,一个简单的向量列表

我有一个地图集合(或列表、序列或向量),如下所示:

{ :name "Bob", :data [32 11 180] }
{ :name "Joe", :data [ 4  8  30] }
{ :name "Sue", :data [10  9  40] }
我想创建新的向量,其中包含与描述数据的键相关联的向量“列”中的数据,如下所示:

{ :ages [32 4 10], :shoe-sizes [11 8 9], :weights [180 30 40] }
实际上,一个简单的向量列表可能就足够了,即:

[32 4 10] [11 8 9] [180 30 40]  

如果把原始列表变成一个向量更好/更容易,那就好了;只要最简单。

您可以像这样使用reduce:

(def data [{ :name "Bob", :data [32 11 180] }
           { :name "Joe", :data [ 4  8  30] }
           { :name "Sue", :data [10  9  40] }])

(reduce 
  (fn [acc {[age shoe-size weight] :data}]
    (-> acc
      (update-in [:ages] conj age)
      (update-in [:shoe-sizes] conj shoe-size)
      (update-in [:weights] conj weight)))
{}
data)
{:weights (40 30 180), :shoe-sizes (9 8 11), :ages (10 4 32)}
返回如下内容:

(def data [{ :name "Bob", :data [32 11 180] }
           { :name "Joe", :data [ 4  8  30] }
           { :name "Sue", :data [10  9  40] }])

(reduce 
  (fn [acc {[age shoe-size weight] :data}]
    (-> acc
      (update-in [:ages] conj age)
      (update-in [:shoe-sizes] conj shoe-size)
      (update-in [:weights] conj weight)))
{}
data)
{:weights (40 30 180), :shoe-sizes (9 8 11), :ages (10 4 32)}
我认为这段代码最有趣的部分是使用嵌套的解构来抓取键:
{[age shoe size weight]:data}

(def records
  [{:name "Bob" :data [32 11 180]}
   {:name "Joe" :data [ 4  8  30]}
   {:name "Sue" :data [10  9  40]}])
您可以进行下一步转换以获得所需的结果:

(->> records
     (map :data) ; extract :data vectors 
     ; => ([32 11 180] [4 8 30] [10 9 40])
     (apply map vector) ; transpose
     ; => ([32 4 10] [11 8 9] [180 30 40])
     (zipmap [:ages :shoe-sizes :weights])) ; make map 
     ; => {:weights [180 30 40], :shoe-sizes [11 8 9], :ages [32 4 10]}
如果没有注释,它看起来更干净一些:

(->> records 
     (map :data)
     (apply map vector)
     (zipmap [:ages :shoe-sizes :weights]))
如果没有宏,则相当于更详细:

(let [extracted (map :data records)
      transposed (apply map vector extracted)
      result (zipmap [:ages :shoe-sizes :weights] transposed)]
  result)

--我刚刚完成了我的解决方案,晚了2分钟,看起来和你的差不多。然而,对我来说,掌握reduce和如何使用reduce比理解解构更难。哇,太快了!非常感谢。我还不明白你的解决方案,但我会胡闹一下,发布一个更新或者接受你的答案。这个答案很好,但由于OP是一个“clojure新手”,你可能想解释一下踩踏宏
(>)
的用法,并可能添加一个带有中间
def
let
s的版本。难以置信!非常感谢。是的,使用
let
的替代方法会有所帮助。试着将我的想法围绕画眉宏…没有线程宏代码看起来几乎相同-我们引入了新的中间绑定,而不是将转换结果直接传递到下一步。不过,我同意这个版本(尽管有点冗长)可能更具可读性。现在答案更新了。好的,我仍然不完全理解这两个“画眉”宏
->
->
()之间的区别,但是使用
宏扩展所有
会有所帮助。例如,如果没有zipmap部件,它将扩展为
(应用映射向量(映射:数据记录))
。感谢
let
版本。都很有帮助。