Clojure - 对列表列表中的每个项目进行操作

时间:2015-11-15 22:26:43

标签: list clojure functional-programming return-value

我正在Clojure开展我的第一个功能项目。我有一些问题要弄清楚如何遍历列表中的每个项目,列表中的每个列表,并在保持返回值的同时对其进行操作。我确定问题来自于我对Clojure和函数式编程的不熟悉,并且希望有人可以解释执行以下操作的最佳方法:

psuedo-code algorithm:
for each lst in list
   for each item in lst
      return_values.append = do_something(item)

我首先尝试嵌套两个doseq函数,然后调用我的do_something函数,该函数调用项目上的函数,但没有保存我的返回值。然后,我尝试将forcons添加到空列表中,但无法在for之外获取返回值。

首先打破列​​表列表是否可能/更可取?我还能得到一份返回值列表吗?

最后,我希望结果是一个返回值列表列表,以匹配列表的输入列表。 如果有人能够解释在Clojure中做到这一点的最佳方法,以及为什么,我们将非常感激。

3 个答案:

答案 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元素调用,该元素作为第二个参数传递。结果将以与输入结构相同的嵌套结构返回。