sve*_*hie 0 dictionary functional-programming clojure
我有这样的地图(有1个或多个项目混合在一起):
{:item_name_1 "Great Deal"
:item_options_2 "blah: 2"
:item_name_2 "Awesome Deal"
:item_options_1 "foo: 3"
:item_quantity_1 "1"
:item_price_2 "9.99"
:item_price_1 "9.99"
:itemCount "2"}
Run Code Online (Sandbox Code Playgroud)
我想把它变成这样:
[{:item_quantity "1"
:item_options "blah"
:item_name "Great Deal"
:item_price "9.99"}
{:item_name "Awesome Deal"
:item_options "foo"
:item_quantity "1"
:item_price "9.99"}]
Run Code Online (Sandbox Code Playgroud)
所以,我想通过项目键将它们分开:
(def item-keys [:item_name :item_options :item_price :item_quantity])
Run Code Online (Sandbox Code Playgroud)
我猜我可能会以某种方式使用map或者walk我看不到该怎么做 - 我对Clojure很新.
我先说
(defn parse-items
[mixed-map]
(let [num-items (Integer/parseInt (:itemCount mixed-map))]
(into []
(do-something mixed-map))))
Run Code Online (Sandbox Code Playgroud)
我猜这个问题可以重新定义如下.
如果这些假设是正确的,这是我的解决方案.
首先,定义一个名为的辅助函数,kv->skv它将原始键值对([k v])转换为后缀的向量和修改后的键值对([suffix [k' v]).
user> (def items {:item_name_1 "Great Deal"
:item_options_2 "blah: 2"
:item_name_2 "Awesome Deal"
:item_options_1 "foo: 3"
:item_quantity_1 "1"
:item_price_2 "9.99"
:item_price_1 "9.99"
:itemCount "2"})
#'user/items
user> (defn- kv->skv
[[k v]]
(let [[_ k' s] (re-find #"(.+)_(\d+)" (name k))]
[s [k' v]]))
#'user/kv->skv
user> (def items' (map kv->skv items))
#'user/items'
user> (clojure.pprint/pprint items')
(["1" ["item_name" "Great Deal"]]
["2" ["item_options" "blah: 2"]]
["2" ["item_name" "Awesome Deal"]]
["1" ["item_options" "foo: 3"]]
["1" ["item_quantity" "1"]]
["2" ["item_price" "9.99"]]
["1" ["item_price" "9.99"]]
[nil [nil "2"]])
nil
Run Code Online (Sandbox Code Playgroud)
然后,使用项目键过滤项目.
user> (def item-keys #{:item_name :item_options :item_price :item_quantity})
#'user/item-keys
user> (def items-filtered (filter (comp item-keys keyword first second) items'))
#'user/items-filtered
user> (clojure.pprint/pprint items-filtered)
(["1" ["item_name" "Great Deal"]]
["2" ["item_options" "blah: 2"]]
["2" ["item_name" "Awesome Deal"]]
["1" ["item_options" "foo: 3"]]
["1" ["item_quantity" "1"]]
["2" ["item_price" "9.99"]]
["1" ["item_price" "9.99"]])
nil
Run Code Online (Sandbox Code Playgroud)
其次,使用该group-by函数按后缀对组修改键值对.
user> (def groupings (group-by first items-filtered))
#'user/groupings
user> (clojure.pprint/pprint groupings)
{"1"
[["1" ["item_name" "Great Deal"]]
["1" ["item_options" "foo: 3"]]
["1" ["item_quantity" "1"]]
["1" ["item_price" "9.99"]]],
"2"
[["2" ["item_options" "blah: 2"]]
["2" ["item_name" "Awesome Deal"]]
["2" ["item_price" "9.99"]]]}
nil
Run Code Online (Sandbox Code Playgroud)
并将分组转换为地图.
user> (def what-you-want (->> (vals groupings)
(map #(->> %
(map second)
(into {})))))
#'user/what-you-want
user> (clojure.pprint/pprint what-you-want)
({"item_name" "Great Deal",
"item_options" "foo: 3",
"item_quantity" "1",
"item_price" "9.99"}
{"item_options" "blah: 2",
"item_name" "Awesome Deal",
"item_price" "9.99"})
nil
Run Code Online (Sandbox Code Playgroud)
最后,将这些步骤集成到一个函数中.
(defn extract-items
[items item-keys]
(let [kv->skv (fn
[[k v]]
(let [[_ k' s] (re-find #"(.+)_(\d+)" (name k))]
[s [k' v]]))]
(->> items
(map kv->skv)
(filter (comp item-keys keyword first second))
(group-by first)
vals
(map #(->> %
(map second)
(into {}))))))
Run Code Online (Sandbox Code Playgroud)
有用.
user> (clojure.pprint/pprint (extract-items items item-keys))
({"item_name" "Great Deal",
"item_options" "foo: 3",
"item_quantity" "1",
"item_price" "9.99"}
{"item_options" "blah: 2",
"item_name" "Awesome Deal",
"item_price" "9.99"})
nil
Run Code Online (Sandbox Code Playgroud)
我希望这种循序渐进的方法可以帮助您.