迭代clojure映射对(循环)

时间:2022-03-08 19:28:25

I have a sequence of map-pairs like this (currently about 17000 pairs)

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

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

I want to filter specific pairs into a new sequence with

我想用特定的对将特定的对过滤成新的序列

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

I have been trying to iterate with loop like this but keep getting thread-death. Also if I use filter on a a single map collection it just returns a new sequence, not sure if I need to create one myself here?

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

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

Finnally is looping the most efficient way to get the new sequence of pairs?

Finnally正在循环最有效的方式来获得新的对序列?

Best, J

最好,J

2 个解决方案

#1


8  

No need for loop/recur here. filter already iterates through a seq for you:

这里不需要循环/重复。 filter已经为你迭代了seq:

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

#2


6  

First thing to know is that (most of) the data structures in clojure are immutable and most functions are, well, functional. That means, that they don't have side effects. In your case filter doesn't change the sequence in any way, it returns a new one, containing only the unfiltered items.

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

So, to filter myseq you need to do something like:

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

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

Filter will call the function repeatedly, binding xto the currently filtered item in myseq. That is, the first time it'll be bound to {:name "Peter" :rank 2222}, then to {:name "Anna" :rank 111}. The filtered-seq will contain only the elements, for which the function returned true. myseq will not be modified!

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

So, you want to leave only elements with :rank higher than 222:

所以,你想只留下以下元素:排名高于222:

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

That's it. And one more thing about filter is, that it's lazy. That is, items in the returned collection are "realized" (or computed) only when they are needed.

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

You don't need to use loop for this, as filter does the job nicely, and loop isn't lazy.

你不需要为此使用循环,因为过滤器很好地完成了工作,并且循环不是懒惰的。

That said, your loop doesn't work because it has several problems:

也就是说,你的循环不起作用,因为它有几个问题:

  1. recur is outside the loop. In this case clojure will loop back to the beginning of the function.
  2. recur在循环之外。在这种情况下,clojure将循环回函数的开头。
  3. you need to construct a return value and you need to maintain the "current" element
  4. 你需要构造一个返回值,你需要维护“当前”元素
  5. you need to properly check for the end condition
  6. 你需要正确检查结束条件

The code could look something like this (untested):

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

(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))))))

Note how:

请注意:

  1. recur is now inside the loop
  2. recur现在在循环中
  3. res contains the return value and sq contains the currently left sequence
  4. res包含返回值,sq包含当前左侧序列
  5. each recur passes the new values of sq and res for the next iteration
  6. 每个recur都会传递sq和res的新值以进行下一次迭代
  7. sq is "shrinked" with each iteration, so the loop will eventually exit unless myseq is infinite. Contrast this to filter, which handles infinite sequences just fine.
  8. 每次迭代时sq都会“缩小”,因此除非myseq是无限的,否则循环最终会退出。将此与过滤器进行对比,过滤器可以很好地处理无限序列。

As you see this is harder to read and less general than filter and also is eager (not lazy).

正如你所看到的那样,它比过滤器更难阅读并且不那么通用,而且也很渴望(不是懒惰)。

#1


8  

No need for loop/recur here. filter already iterates through a seq for you:

这里不需要循环/重复。 filter已经为你迭代了seq:

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

#2


6  

First thing to know is that (most of) the data structures in clojure are immutable and most functions are, well, functional. That means, that they don't have side effects. In your case filter doesn't change the sequence in any way, it returns a new one, containing only the unfiltered items.

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

So, to filter myseq you need to do something like:

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

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

Filter will call the function repeatedly, binding xto the currently filtered item in myseq. That is, the first time it'll be bound to {:name "Peter" :rank 2222}, then to {:name "Anna" :rank 111}. The filtered-seq will contain only the elements, for which the function returned true. myseq will not be modified!

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

So, you want to leave only elements with :rank higher than 222:

所以,你想只留下以下元素:排名高于222:

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

That's it. And one more thing about filter is, that it's lazy. That is, items in the returned collection are "realized" (or computed) only when they are needed.

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

You don't need to use loop for this, as filter does the job nicely, and loop isn't lazy.

你不需要为此使用循环,因为过滤器很好地完成了工作,并且循环不是懒惰的。

That said, your loop doesn't work because it has several problems:

也就是说,你的循环不起作用,因为它有几个问题:

  1. recur is outside the loop. In this case clojure will loop back to the beginning of the function.
  2. recur在循环之外。在这种情况下,clojure将循环回函数的开头。
  3. you need to construct a return value and you need to maintain the "current" element
  4. 你需要构造一个返回值,你需要维护“当前”元素
  5. you need to properly check for the end condition
  6. 你需要正确检查结束条件

The code could look something like this (untested):

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

(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))))))

Note how:

请注意:

  1. recur is now inside the loop
  2. recur现在在循环中
  3. res contains the return value and sq contains the currently left sequence
  4. res包含返回值,sq包含当前左侧序列
  5. each recur passes the new values of sq and res for the next iteration
  6. 每个recur都会传递sq和res的新值以进行下一次迭代
  7. sq is "shrinked" with each iteration, so the loop will eventually exit unless myseq is infinite. Contrast this to filter, which handles infinite sequences just fine.
  8. 每次迭代时sq都会“缩小”,因此除非myseq是无限的,否则循环最终会退出。将此与过滤器进行对比,过滤器可以很好地处理无限序列。

As you see this is harder to read and less general than filter and also is eager (not lazy).

正如你所看到的那样,它比过滤器更难阅读并且不那么通用,而且也很渴望(不是懒惰)。