Clojure 如何比较向量中连续元素的值进行过滤?
我需要过滤一个给定的向量,这样输出只包含那些不是直接邻居的重复元素Clojure 如何比较向量中连续元素的值进行过滤?,clojure,Clojure,我需要过滤一个给定的向量,这样输出只包含那些不是直接邻居的重复元素 Example : I/P -> [1 1 3 2 2 4 5 5] O/P -> [3 4] 这几乎是一个蛮力解决方案,所以希望我们能看到一些更令人满意的答案,但为了让球滚起来 (defn lonely? "Return the ith element of v if it doesn't have a matching neighbor" [i v] (when (cond
Example : I/P -> [1 1 3 2 2 4 5 5]
O/P -> [3 4]
这几乎是一个蛮力解决方案,所以希望我们能看到一些更令人满意的答案,但为了让球滚起来
(defn lonely?
"Return the ith element of v if it doesn't have a matching neighbor"
[i v]
(when (cond
(zero? i) (not= (v 0) (v 1))
(= i (- (count v) 1)) (not= (v i) (v (- i 1)))
:else (and (not= (v i) (v (- i 1)))
(not= (v i) (v (+ i 1)))))
(v i)))
> (def v [1 1 3 2 2 4 5 5])
> (keep #(lonely? % v) (range (count v)))
(3 4)
请注意,此解决方案还包括两个以上相邻值相同的情况,例如:
(def data-3 [1 1 3 2 2 2 4 5 5 2 5 5])
;[3 4 2]
所有的艰苦工作都在功能减速机中进行
我总是将reduce
的第一个参数标记为“累加器”,第二个参数标记为“新值”
在这种情况下,累加器必须有两部分:正在创建的向量和最后看到的数字。(请注意,如果您只希望成对出现重复项,则不需要看到最后一个数字。)
因此,[vp]
是减速器的“累加器”部分-v
是您正在创建的向量,p
是前面看到的值。n
参数是“新值”
对这4个条件的解释如下:
v
为空,只需使用新值创建一个新向量并记录
新的价值观。这是必要的,因为窥视一个空向量
(下一个条件)将导致异常v
的最后一个值与新值相同,请将其删除并记录
新的价值观n
)与上一个值(p
)相同,则忽略
信息技术这种情况使我们能够消除重复的值
好几次另一种方法是:
(defn remove-consecutive-duplicates [inp]
(let [intm (into [] (partition-by identity inp))]
(reduce (fn [acc n]
(if (= 1 (count n))
(conj acc n)
acc ))
[] intm)))
请注意,重复数据消除不会提供所需的输出。这与@amalloy的答案完全相同,但它使用
传感器
而不是线程宏(->
)
它应该更高效,至少在大型集合上是如此
partitionbyidentity
将coll划分为相同元素的子列表。remove next
会删除next
不是nil的所有子列表(即它们有多个元素)。最后一个map first
获取每个子列表的第一个元素,从而将列表列表展平为元素列表
只需分别运行每个步骤,看看它是如何工作的。基本上是从头开始构建的,您可以通过分解来完成大部分工作:
(defn no-dupes [coll]
(when-let [[x & [y & ys :as xs]] (seq coll)]
(if xs
(if (= x y)
(recur (drop-while #(= x %) ys))
(lazy-seq (cons x (no-dupes xs))))
(list x))))
话虽如此,我在这几行中犯了两个错误,但显然是正确的
这比你的速度快吗
对。它的速度大约是3倍:根据Criterium的数据,大约500纳秒,而这个简短的例子大约是1.5微秒 使用传感器,如@amitr的解决方案,但IMHO,稍微清洁一点:
(def isolate
(comp
(partition-by identity)
(remove next)
cat))
然后,它可以与
序列一起使用,进入,您希望的任何传感器接收功能。对于[1 1 3 2 4 5 2 5]
,输出应该是什么?(最后一个2
是否因为序列前面有重复的2
而被丢弃?还是因为没有另一个2
作为邻居而保留?)输出应为[3 4 2]否。它很容易解释,并且使用的函数很容易查找。如果堆栈溢出不需要这样的答案,欢迎他们将其删除。或者将展平,而不是(映射优先)
@fl00r否,这将是非常错误的。尝试输入[[12][12]]
@amalloy,但是(下一步删除)
已经删除了所有非单一序列,不是吗?@fl00r是的,我们有一个单一序列列表。但是,该单例列表中的项本身可能是一个列表,您不应该将其展平。不过,我的示例输入是错误的:它应该没有重复项<代码>(按标识[[12]]划分)
,例如,生成([12]))
remove next
不会更改它,但是我们想要的结果是([12])
(即,输入保持不变)<代码>首先映射
会产生这种效果,但是使用展平
会产生(12)
,这是一种过度的展平。重复数据消除
,而不是重复数据消除
?
(defn isolate [coll]
(transduce
(comp
(partition-by identity)
(remove next)
(map first))
conj coll))
(defn no-dupes [coll]
(when-let [[x & [y & ys :as xs]] (seq coll)]
(if xs
(if (= x y)
(recur (drop-while #(= x %) ys))
(lazy-seq (cons x (no-dupes xs))))
(list x))))
(def isolate
(comp
(partition-by identity)
(remove next)
cat))