Recursion 重组Clojure中的地图。将当前映射中的相应值转换为新映射
我想知道实现以下目标最惯用的方法是什么。我刚刚开始使用Clojure,我正在努力寻找不依赖传统迭代构造(for、while等)的数据结构操作策略 如果我的地图结构如下所示:Recursion 重组Clojure中的地图。将当前映射中的相应值转换为新映射,recursion,clojure,iteration,Recursion,Clojure,Iteration,我想知道实现以下目标最惯用的方法是什么。我刚刚开始使用Clojure,我正在努力寻找不依赖传统迭代构造(for、while等)的数据结构操作策略 如果我的地图结构如下所示: (def test-map {:cat1-title "Title1", :cat1-val "Value1", :cat2-title "Title2", :cat2-val "Value2"}) 我想将其转换为以下结构: {"Title1" "Value1", "Title2" "Value2"} 本质上,我想制作一
(def test-map {:cat1-title "Title1", :cat1-val "Value1", :cat2-title "Title2", :cat2-val "Value2"})
我想将其转换为以下结构:
{"Title1" "Value1", "Title2" "Value2"}
本质上,我想制作一个新的地图,其键是*标题键的值,这些值是对应*值键的值
这样做的最佳clojure方法是什么
我尝试了以下几点(我不知道它是否总是有效)。它本质上提取*title值,然后用提取的*val值对其进行压缩
(let [titles
(vals (filter #(re-matches #".*-title"
(str (key %)))
test-map))
values
(vals (filter #(re-matches #".*-val"
(str (key %)))
test-map))]
(zipmap titles values))
这成功地提取了键和值,但我不确定使用zipmap将它们压缩在一起是最好的方式,还是最惯用的方式来组合它们。zipmap对于较大的映射将失败,因为键/值对在映射中没有严格的顺序。对于小贴图,它们通常遵循您创建它们的顺序,因为小贴图是作为PersistentArrayMaps创建的。大型地图是永久性的地图。观察
(应用哈希映射(范围100))
vs(应用哈希映射(范围10))
的结果,因此如果您有一个更大的映射,您的-title将不会与您的-vals对齐
不幸的是,这意味着您确实需要查找与标题明确匹配的VAL。有一种方法可以做到这一点:
(defn transform [m]
(into {} (for [[k v] m
:let [title (name k)]
:when (.endsWith title "-title")
:let [val-name (clojure.string/replace title #"-title$" "-val")]]
[v (m (keyword val-name))])))
对于以标题结尾的每个键,查找具有相同前缀的val,并将其全部放在地图中。我将以类似于Timothy的方式回答此问题,但对于生产代码,我认为最好分散一些内容,并更明确一些:
(ns clj.core
(:require [clojure.string :as str] )
(:use tupelo.core)) ; it->
(defn is-title-kw [arg] (re-matches #".*-title" (name arg)))
(defn title-kw->val-kw [arg] (it-> arg
(name it)
(str/replace it #"-title" "-val")
(keyword it)))
(defn transform [map-arg]
(let [title-kws (filter is-title-kw (keys map-arg)) ]
(into {}
(for [title-kw title-kws]
(let [val-kw (title-kw->val-kw title-kw)
title-str (title-kw map-arg)
val-str (val-kw map-arg) ]
{title-str val-str} )))))
当然,还有一些单元测试:
(ns tst.clj.core
(:use clj.core
clojure.test
tupelo.core))
(def test-map { :cat1-title "Title1", :cat1-val "Value1",
:cat2-title "Title2", :cat2-val "Value2" } )
(deftest t-is-title-kw
(is (is-title-kw :cat1-title))
(is (is-title-kw :cat2-title))
(is (not (is-title-kw :cat1-val)))
(is (not (is-title-kw :cat2-val))))
(deftest t-title-kw->val-kw
(is (= :cat1-val (title-kw->val-kw :cat1-title)))
(is (= :cat2-val (title-kw->val-kw :cat2-title))))
(deftest t-transform
(is (= (transform test-map)
{ "Title1" "Value1",
"Title2" "Value2" } )))
运行测试:
~/clj > lein test
lein test tst.clj.core
Ran 3 tests containing 7 assertions.
0 failures, 0 errors.
我宁愿使用
reduce kv
来实现:
(defn transform [items-map]
(reduce-kv (fn [result k v]
(if-let [[_ name] (re-find #"^:(.+)-title$" (str k))]
(assoc result v (items-map (keyword (str name "-val"))))
result))
{} items-map))
答复:
user> (def test-map {:cat-1-title "Title1", :cat-1-val "Value1",
:cat2-title "Title2", :cat2-val "Value2",
:cat3-title "Title3", :cat3-val "Value3"})
#'user/test-map
user> (transform test-map)
{"Title1" "Value1", "Title2" "Value2", "Title3" "Value3"}
你能发布一个尝试,让我们有更多的事情要做吗?大部分问题是我根本不知道如何处理它,但我可以用我尝试过的内容进行编辑。是的,即使你不太确定要去哪里,看到你迄今为止尝试过的东西还是很好的。