【问题标题】:Iterate over clojure map pairs (loop)遍历 clojure 映射对(循环)
【发布时间】:2023-03-15 16:23:01
【问题描述】:

我有一系列这样的地图对(目前大约 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))))

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

【问题讨论】:

    标签: loops dictionary clojure


    【解决方案1】:

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

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

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

    Filter 将重复调用该函数,将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. recurloop 之外。在这种情况下,clojure 将循环回到函数的开头。
    2. 你需要构造一个返回值并且你需要维护“当前”元素
    3. 您需要正确检查结束条件

    代码可能看起来像这样(未经测试):

    (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 更难阅读,更不通用,而且也很急切(不是懒惰)。

    【讨论】:

    • 感谢 Ivant,非常棒的反馈!
    【解决方案2】:

    这里不需要循环/重复。 filter 已经为您遍历了一个 seq:

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

    【讨论】:

    • 更好!这就是我首先尝试但没有成功的方式。谢谢。
    • (filter #(> (:rank %) 220) myseq)
    • 非常感谢大家,代码现在可以运行而且速度也非常快!
    猜你喜欢
    • 2021-11-22
    • 1970-01-01
    • 2017-02-08
    • 2018-08-22
    • 2019-11-08
    • 2015-06-05
    • 2014-02-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多