我刚刚开始学习Clojure和函数式编程,并且我很难尝试执行以下任务:
我有这样的载体矢量[[a b] [a c] [b c] [c d] [d b]]。我需要遍历它,删除第二列上已出现的第二列上显示的项目。例如项目[b c]和[d b](因为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]]
如你所见,c和d分别已经出现在前面的项目[a c]和[c d]上,所以我必须删除项目[b c]和[a d]。
到目前为止,我有以下代码
此函数返回要删除的项目向量。在我们的场景中,它返回向量[[b c] [a d]]
(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)))
)
]))
])))
我认为递归可以解决我的问题,但我会感谢任何帮助来完成这项工作:)。
提前致谢。
答案 0 :(得分:3)
实现此目的的一种方法是使用reduce
:
(first (reduce (fn [[result previous] [a b]]
[(if (contains? previous b)
result
(conj result [a b]))
(conj previous b)])
[[] #{}]
'[[a b] [a c] [b c] [c d] [d b]]))
;=> [[a b] [a c] [c d]]
我们希望跟踪到目前为止我们已经建立的结果(result
)以及我们之前在第二列(previous
)中找到的项目集。然后,对于每个新项[a b]
,我们会检查previous
是否包含第二项b
。如果是,我们不会向result
添加任何内容。否则,我们conj
将新项目[a b]
添加到result
的末尾。我们还conj
将第二项b
previous
改为previous
。由于previous
是一个集合,如果b
已经包含reduce
,则不会执行任何操作。最后,在first
完成后,我们从结果中获取{{1}}项,这代表了我们的最终答案。
答案 1 :(得分:2)
如果我理解你的问题,应该这样做:
(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"]]
。
答案 2 :(得分:2)
如果您可以依赖示例中的重复项,请使用
(->> '[[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 distinct
传感器实现distinct-by
传感器。
(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)))))))))
答案 3 :(得分:1)
以下内容与@Elogent's answer类似,但使用: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]]
答案 4 :(得分:0)
只是为了好玩:
这些不保留结果的顺序,但是如果你没关系,那么它们非常具有表现力(重复可以是任何顺序,与上面的// unknown content closure
let someHashBashing : (String) -> Bool = {
return $0 == "axk"
}
// setup alphabet
let alphabet = [Character]("abcdefghijklmnopqrstuvwxyz".characters)
// any success for 500 attempts?
let firstAttempt = bruteForce(someHashBashing, forAlphabet: alphabet,
forWordLength: 3, forNumberOfAttempts: 500)
if let password = firstAttempt.1 {
print("Password cracked: \(password) (attempt \(firstAttempt.0))")
}
// if not, try another 500?
else {
if case (let i, .Some(let password)) =
bruteForce(someHashBashing, forAlphabet: alphabet,
forWordLength: 3, forNumberOfAttempts: 500,
startingFrom: firstAttempt.0) {
print("Password cracked: \(password) (attempt \(i))")
} /* Password cracked: axk (attempt 608) */
}
变体不同):
一个是按第二个值对所有内容进行分组,并从每个val中取出第一个项目:
partition-by
使用有序集合还有一种很好的方法:
(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]}
但是,我认为loop / recur总是更快:
(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])