Recursion Clojure-从循环内的向量中删除项
我刚开始学习Clojure和函数式编程,在尝试实现以下任务时遇到了困难: 我有一个像这样的向量向量[[ab][ac][bc][cd][db]]。我需要遍历它,删除第二列中出现的项目,这些项目已经出现在第二列中。例如,项[bc]和[db](因为c和b都已出现在第二列中)。我设法得到了一个一次删除一个项的函数,但是我需要遍历每个项的向量来检查和删除这些项。我怎样才能做到这一点?我曾想过使用递归来实现这一点,但每次尝试都以失败告终对不起,如果这是一个无关紧要的问题,但我一直坚持着这一点 例如 输入: [a b][a c][b c][c d][a d][b e]] 输出(预期): [a b][a c][c d][b e]] 删除的项目: [b c][a d]]Recursion Clojure-从循环内的向量中删除项,recursion,vector,clojure,functional-programming,Recursion,Vector,Clojure,Functional Programming,我刚开始学习Clojure和函数式编程,在尝试实现以下任务时遇到了困难: 我有一个像这样的向量向量[[ab][ac][bc][cd][db]]。我需要遍历它,删除第二列中出现的项目,这些项目已经出现在第二列中。例如,项[bc]和[db](因为c和b都已出现在第二列中)。我设法得到了一个一次删除一个项的函数,但是我需要遍历每个项的向量来检查和删除这些项。我怎样才能做到这一点?我曾想过使用递归来实现这一点,但每次尝试都以失败告终对不起,如果这是一个无关紧要的问题,但我一直坚持着这一点 例如 输入:
(defn find-invalid [collection-data item-to-check]
(subvec (vec (filter #(= (second %) item-to-check) collection-data)) 1))
(defn find-invalid [collection-data item-to-check]
(subvec (vec (filter #(= (second %) item-to-check) collection-data)) 1))
如您所见,c和d已经分别出现在前面的项目[AC]和[CD]上,因此我必须删除项目[BC]和[AD]
到目前为止,我有以下代码
此函数返回要删除的项的向量。在我们的场景中,它返回向量[[bc][ad]]
(defn find-invalid [collection-data item-to-check]
(subvec (vec (filter #(= (second %) item-to-check) collection-data)) 1))
(defn find-invalid [collection-data item-to-check]
(subvec (vec (filter #(= (second %) item-to-check) collection-data)) 1))
另一个函数通过项的给定索引从原始向量中一次删除一个项
(defn remove-invalid [collection-data item-position]
(vec (concat (subvec collection-data 0 item-position) (subvec collection-data (inc item-position)))))
最后一个函数就是我用来测试这个逻辑的
(defn remove-invalid [original-collection ]
(dorun (for [item original-collection]
[
(dorun (for [invalid-item (find-invalid original-collection (second item))]
[
(cond (> (count invalid-item) 0)
(println (remove-invalid original-collection (.indexOf original-collection invalid-item)))
)
]))
])))
我认为递归可以解决我的问题,但我希望能得到任何帮助:)
提前感谢。如果我正确理解了您的问题,这应该可以做到:
(defn clear [v]
(loop [v v existing #{} acc []]
(if (empty? v)
acc
(recur (rest v)
(conj existing (second (first v)))
(if (some existing [(ffirst v)]) acc (conj acc (first v)))))))
使用循环/重现解决。如果我有时间的话,我会看看是否可以使用reduce之类的函数,或者任何合适的函数
此过滤器:
[[“a”b”][“a”c”][“b”c”][“c”d”][“d”b”]
到[[“a”b”][“a”c”]
实现此功能的一种方法是使用:
我们希望跟踪到目前为止建立的结果(
result
)以及之前在第二列中找到的项目集(previous
)。对于每个新项目[ab]
,我们检查之前的是否包含第二个项目b
。如果有,我们不会向结果添加任何内容。否则,我们将新项目[ab]
连接到结果的末尾。我们还将第二项b
合并到之前的中。由于previous
是一个集合,如果previous
已包含b
,则该集合不会起任何作用。最后,在reduce
完成后,我们从结果中获取第一个项,它代表我们的最终答案。以下内容类似于,但使用:as
子句来避免重新构建内容:
(defn filtered [stuff]
(second
(reduce
(fn [[seconds ans :as sec-ans] [x y :as xy]]
(if (seconds y)
sec-ans
[(conj seconds y) (conj ans xy)]))
[#{} []]
stuff)))
比如说,
(filtered '[[a b] [a c] [b c] [c d] [d b]])
;[[a b] [a c] [c d]]
如果您可以像示例中那样依赖于重复项是连续的,请使用
(->> '[[a b] [a c] [b c] [c d] [a d] [b e]]
(partition-by second)
(map first))
;-> ([a b] [a c] [c d] [b e])
否则,在Clojures传感器的基础上实现一个<代码>由<代码>区分的传感器
(sequence (distinct-by second)
'[[a b] [a c] [b c] [c d] [a d] [b e]])
;-> ([a b] [a c] [c d] [b e])
实施
(defn distinct-by [f]
(fn [rf]
(let [seen (volatile! #{})]
(fn
([] (rf))
([result] (rf result))
([result input]
(let [vinput (f input)] ; virtual input as seen through f
(if (contains? @seen vinput)
result
(do (vswap! seen conj vinput)
(rf result input)))))))))
只是为了好玩:
这些选项不保留结果的顺序,但如果您同意的话,它们非常具有表现力(重复项可以是任意顺序,不同于上面的分区方式
):
一种是根据第二个值对所有内容进行分组,并从每个val中获取第一项:
(map (comp first val)
(group-by second '[[a b] [a c] [b c] [c d] [a d] [b e]]))
;; => ([a b] [a c] [c d] [b e])
还有一种很好的方法,使用排序集:
(into (sorted-set-by #(compare (second %1) (second %2)))
'[[a b] [a c] [b c] [c d] [a d] [b e]])
;; => #{[a b] [a c] [c d] [b e]}
还有一个,也是不遵守秩序的:
(vals (into {} (map (juxt second identity)
(rseq '[[a b] [a c] [b c] [c d] [a d] [b e]]))))
;; => ([b e] [c d] [a c] [a b])
但是是的,循环/重现总是更快,我想:
(defn remove-dupes [v]
(loop [[[_ i2 :as pair] & xs :as v] v present #{} res []]
(cond (empty? v) res
(present i2) (recur xs present res)
:else (recur xs (conj present i2) (conj res pair)))))
好问题。我相信clojure专业人士会来解围=]