迭代clojure映射对(循环)

时间:2012-07-24 07:44:00

标签: loops dictionary clojure

我有一系列像这样的地图对(目前约有17000对)

(def myseq '({:name "Peter" :rank 2222} {:name "Anna" :rank 111}))

我想使用

将特定对过滤成新序列
(filter (fn [x] (> x 222)) (:rank (first myseq)))

我一直试图像这样循环迭代,但一直在线程死亡。此外,如果我在单个地图集合上使用过滤器,它只返回一个新序列,不确定我是否需要在这里创建一个?

(defn remove-lower [number myseq]
    (loop [i 0]
        (if (= i (count file))
            (println "done")
            (filter [x] (> x number))
                (:rank (first myseq))))
    (recur (rest myseq))))

最后循环最有效的方法来获得新的对序列?

2 个答案:

答案 0 :(得分:8)

这里不需要循环/重复。过滤器已经为你迭代了一个seq:

(filter (fn [entry] (> (:rank entry) 220)) myseq)

答案 1 :(得分:6)

首先要知道的是(大多数)clojure中的数据结构是不可变的,而且大多数函数都是功能。这意味着,他们没有副作用。在您的情况下,filter不会以任何方式更改序列,它会返回一个新序列,仅包含未过滤的项目。

因此,要过滤myseq,您需要执行以下操作:

(def filtered-seq (filter (fn [x] ...) myseq))

过滤器将重复调用该函数,将x绑定到myseq中当前过滤的项目。也就是说,它第一次绑定到{:name "Peter" :rank 2222},然后绑定到{:name "Anna" :rank 111}filtered-seq将仅包含函数返回true的元素。 myseq进行修改!

因此,您只想保留:rank高于222的元素:

(filter (fn [x] (> (:rank x) 222)) myseq)

就是这样。关于过滤器的另一件事是,它是懒惰的。也就是说,只有在需要时才会“实现”(或计算)返回集合中的项目。

您无需使用loop,因为filter可以很好地完成工作,loop并不是懒惰。

那就是说,你的loop不起作用,因为它有几个问题:

  1. recur位于loop之外。在这种情况下,clojure将循环回函数的开头。
  2. 您需要构建一个返回值,并且需要维护“当前”元素
  3. 您需要正确检查结束条件
  4. 代码看起来像这样(未经测试):

    (defn remove-lower [number myseq]
      (loop [sq myseq res []]
         (if (empty? sq)
             res
             (let [current (first sq)]
               (if (> (:rank current) number)
                  (recur (rest sq) (conj res current))
                  (recur (rest sq) res))))))
    

    请注意:

    1. recur现在位于loop
    2. res包含返回值,sq包含当前左侧序列
    3. 每个recur传递sqres的新值以进行下一次迭代
    4. sq每次迭代都会“缩小”,因此除非myseq为无限,否则循环最终会退出。将其与filter进行对比,filter处理无限序列就好了。
    5. 如你所见,这比{{1}}更难阅读,也不那么笼统,而且也很渴望(不是懒惰)。