【发布时间】:2016-06-03 00:58:51
【问题描述】:
我有这个字符串向量:
["Color: Black"
"Color: Blue"
"Size: S"
"Size: XS"]
如何获取color 和Size 的所有值?
例如,输出应该是
["color" ["Black" "Blue"]]
【问题讨论】:
标签: dictionary vector clojure
我有这个字符串向量:
["Color: Black"
"Color: Blue"
"Size: S"
"Size: XS"]
如何获取color 和Size 的所有值?
例如,输出应该是
["color" ["Black" "Blue"]]
【问题讨论】:
标签: dictionary vector clojure
此解决方案按属性名称(颜色、大小等)拆分每个字符串、分组,然后清理预期值:
user=> (require '[clojure.string :as string])
nil
user=> (def attributes ["Color: Black" "Color: Blue" "Size: S" "Size: XS"])
#'user/attributes
user=> (as-> attributes x
#_=> (map #(string/split % #": ") x)
#_=> (group-by first x)
#_=> (reduce-kv #(assoc %1 %2 (mapv second %3)) {} x))
{"Color" ["Black" "Blue"], "Size" ["S" "XS"]}
【讨论】:
as-> 宏的巧妙使用。
as-> 可以很容易地替换为->>,因为x 是所有形式中的最后一个参数。此外,对集合进行 3 次完整传递(map、group-by、reduce-kv + mapv 对于每个组),更不用说一堆中间集合,看起来真的是多余的。因此,展示 clojure 序列函数的强大功能是一个很好的答案,但如果您想在生产环境中实际使用它,那真的很糟糕。
as-> 是因为它的清晰度和灵活性(当我想添加一个不符合其他步骤的参数顺序的步骤时,我可以这样做)。我认为这个解决方案以多次通过为代价很好地展示了每一步。
as-> 用于不同的聚集位置(毕竟这是它的主要目的),但在这种情况下,我会说它有点混淆。海事组织
我宁愿用reduce 一次性完成(因为它更短并且可能更快):
user> (require '[clojure.string :as cs])
nil
user> (def data ["Color: Black" "Color: Blue" "Size: S" "Size: XS"])
#'user/data
user> (reduce #(let [[k v] (cs/split %2 #": ")]
(update %1 k (fnil conj []) v))
{} data)
{"Color" ["Black" "Blue"], "Size" ["S" "XS"]}
【讨论】:
reduce 传递。但是,我认为除非您习惯于从 reduce 的角度思考,否则最初得出这个解决方案会比较困难。
reduce/fold 是一种“必要的邪恶”)(我的意思是理解的过程,这可能根据我的经验,真的很痛苦)