我正在Clojure开展我的第一个功能项目。我有一些问题要弄清楚如何遍历列表中的每个项目,列表中的每个列表,并在保持返回值的同时对其进行操作。我确定问题来自于我对Clojure和函数式编程的不熟悉,并且希望有人可以解释执行以下操作的最佳方法:
psuedo-code algorithm:
for each lst in list
for each item in lst
return_values.append = do_something(item)
我首先尝试嵌套两个doseq
函数,然后调用我的do_something
函数,该函数调用项目上的函数,但没有保存我的返回值。然后,我尝试将for
和cons
添加到空列表中,但无法在for
之外获取返回值。
首先打破列表列表是否可能/更可取?我还能得到一份返回值列表吗?
最后,我希望结果是一个返回值列表列表,以匹配列表的输入列表。 如果有人能够解释在Clojure中做到这一点的最佳方法,以及为什么,我们将非常感激。
答案 0 :(得分:5)
嵌套for
循环可以解决这个问题:
(for [lst my-list]
(for [item lst] (do_something item)))
它将采用嵌套列表my-list
(列表列表),并通过将do_something
应用于每个元素将其转换为另一个嵌套列表。
在clojure中,for
已经返回一个值列表,因此无需自己处理。此外,由于clojure中的所有数据结构都是不可变的,因此您无法通过使用cons
将元素附加到最初为空的列表来执行此操作。
答案 1 :(得分:0)
如果您有一个深度嵌套的列表,并且想要保留其结构,但是要转换值,则可以使用clojure.walk/postwalk
对每个值进行操作,例如:
(def nested '(1 (2 3 (4 5)) 6))
(defn transform-values [coll f]
(clojure.walk/postwalk #(if (not (list? %))
(f %)
%)
coll))
(transform-values nested inc)
=> (2 (3 4 (5 6)) 7)
当然,您可以将任何功能传递给transform-values
。
答案 2 :(得分:0)
这可以作为简单的递归步行来完成。对于这一点,首先想到的实现将是以下序列:
(defn deep-walk
[f data]
(map (fn [s] (if (seq? s)
(deep-walk f s)
(f s)))
data))
矢量的这种微小变化:
(defn vec-deep-walk
[f data]
(vec (map (fn [s] (if (vector? s)
(vec-deep-walk f s)
(f s)))
data)))
快速测试以下内容:
(vec-deep-walk (partial + 1) [1 [2 3] 4 [5 [6 7]]])
提供以下输出:
[2 [3 4] 5 [6 [7 8]]]
walk函数有两个参数,第一个是带一个参数的函数。这将针对数据中的每个非seq / vector元素调用,该元素作为第二个参数传递。结果将以与输入结构相同的嵌套结构返回。