如何比较向量中连续元素的值以进行过滤?

时间:2019-02-14 20:38:10

标签: clojure

我需要过滤给定的向量,以便输出仅包含那些不是直接邻居的重复元素。

Example : I/P -> [1 1 3 2 2 4 5 5]
          O/P -> [3 4]

7 个答案:

答案 0 :(得分:8)

(defn isolated [coll]
  (->> coll
       (partition-by identity)
       (remove next)
       (map first)))

答案 1 :(得分:6)

这与@amalloy的答案完全相同,但是它使用transducers而不是线程宏(->>)。

(defn isolate [coll]
  (transduce
   (comp
   (partition-by identity)
   (remove next)
   (map first))
  conj coll))

它应该更有效,至少在大型馆藏上更是如此。

partition-by identity分区归为相同元素的子列表。 remove next删除next不为零的所有子列表(即,它们具有多个元素)。最后一个map first占据每个子列表的第一个元素,从而将列表的列表展平为元素列表。

只需分别运行每个步骤,以了解其工作原理。

答案 2 :(得分:4)

使用类似@amitr解决方案的换能器,但是恕我直言,更干净一些:

(def isolate
  (comp
   (partition-by identity)
   (remove next)
   cat))

然后可以将其与sequenceinto一起使用,无论您想要哪种换能器接收功能。

答案 3 :(得分:2)

这几乎是一种蛮力解决方案,因此希望我们能看到一些更令人满意的答案,但要使工作顺利进行……

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

答案 4 :(得分:2)

(def data-1 [1 1 3 2 2 4 5 5])

(def data-2 [1 1 3 2 2 4 5 5 2 5 5])

(defn reducer [[v p] n]
  (cond
    (empty? v) [[n] n]
    (= (peek v) n) [(pop v) n]
    (= n p) [v n]
    :else [(conj v n) n]))

(first (reduce reducer [[] nil] data-1))
;[3 4]

(first (reduce reducer [[] nil] data-2))
;[3 4 2]

请注意,此解决方案还涵盖了两个以上相邻值相同的情况,例如:

(def data-3 [1 1 3 2 2 2 4 5 5 2 5 5])
;[3 4 2]

所有艰苦的工作都在功能简化器中进行。

从心理上讲,我总是将reduce的第一个参数标记为“累加器”,将第二个参数标记为“新值”。

在这种情况下,累加器必须具有两个部分:正在创建的向量和最后看到的数字。 (请注意,如果您只希望重复项成对出现,那么最后看到的数字是不必要的。)

因此,[v p]是减速器的“累加器”部分-v是要创建的向量,p是先前看到的值。 n参数是“新值”。

这四个条件的解释是:

  1. 如果v为空,只需用新值创建一个新向量并记录 新的价值。这是必要的,因为偷看空向量 (下一个条件)将导致异常。
  2. 如果v的最后一个值与新值相同,请将其删除并记录 新值。
  3. 如果新值(n)与上一个值(p)相同,则忽略 它。这种情况使我们能够消除重复的值 几次。
  4. 如果所有这些条件都不成立,则可以附加值:)

答案 5 :(得分:1)

从头开始或多或少地构建它,您可以进行分解以完成许多工作:

component.install

话虽如此,我在这几行中犯了两个错误,而Alan Malloy's answer显然是正确的。


这比@dpassen's neat transducer version快吗?

是的。根据Criterium的说法,它的速度大约是它的三倍:大约500纳秒,而简短示例大约为1.5微秒。

答案 6 :(得分:0)

另一种方法:

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

请注意,重复数据删除无法提供所需的输出。