在 Clojure 中使用高阶函数处理更改列表

Process a changing list using a higher-order function in Clojure

有没有什么方法可以在 Clojure 中使用高阶函数来处理更改列表,而 不能 使用显式递归?例如,考虑以下问题(我编造的是为了说明我的想法):

Problem: Given a list of unique integers of unknown order. Write a that produces an output list as follows:

  1. For any even integer, keep the same relative position in the output list.
  2. For any odd integer, multiply by ten, and put the new number at a new place: at the back of the original list.

So for example, from original vector [1 2 3 4 5], we get: [2 4 10 30 50]

我知道如何使用显式递归来解决这个问题。例如:

(defn process
  [v]
  (loop
   [results []
    remaining v]
   (if (empty? remaining)
    results
    (if (even? (first remaining))
     (recur (conj results (first remaining)) (rest remaining))
     (recur results (conj (vec (rest remaining)) (* 10 (first remaining))))))))

这很好用。请注意 remaining 随着函数的工作而改变。我也在做这里的整理工作:将元素从 remaining 改组到 results。我想做的是使用一个高阶函数来为我做家务。例如,如果 remaining 没有随着函数的工作而改变,我会使用 reduce 并开始这个过程而不用担心 looprecur.

所以我的问题是:是否有任何方法可以使用高阶函数来处理在操作过程中发生变化的输入(在本例中为 v)?

(更多上下文的旁注:这个问题的灵感来自 sub-contains? 函数中的 Advent of Code 2020, Question 7, first part. There, the natural way to approach it, is to use recursion. I do here (in the find-all-containers function; which is the same way other have approached it, for example, here in the find-outer-bags function, or here。)

不用递归比用递归容易得多!由于您只关心偶数相对于其他偶数的顺序,赔率也是如此,您可以首先将列表一分为二。然后,将正确的函数映射到每个函数上,并简单地连接结果。

(defn process [xs]
  (let [evens (filter even? xs)
        odds (filter odd? xs)]
    (concat evens (map #(* 10 %) odds))))

关于代码问题的出现,我建议使用比列表或向量更好的数据结构。地图是表示正在发生的事情的更好方式,因为您可以轻松地按名称查找每个子包的属性。如果您有从袋子颜色到内容的映射,您可以编写一个简单的(递归)函数来询问:“颜色 a 可以包含颜色 b 吗?”对于叶节点,答案是否定的,对于等于目标颜色的节点,答案是肯定的,对于分支,您递归内容。