这应该很容易,但我发现它比预期更困难。
给定[0 1 2 0 1 2 0 1]
,在每次出现2
之后拆分序列。
结果应与[[0 1 2] [0 1 2] [0 1]]
类似。
split
函数仅在第一个实例中拆分。我的想象力也限于如何使用partition
函数来实现这一目标。
答案 0 :(得分:2)
以前的解决方案都可以(虽然@magos解决方案在某些情况下有缺陷),但如果将此函数用作实用程序(我猜这是相当普遍的),我会使用经典的迭代方法:
(defn group-loop [delim coll]
(loop [res [] curr [] coll (seq coll)]
(if coll
(let [group (conj curr (first coll))]
(if (= delim (first coll))
(recur (conj res group) [] (next coll))
(recur res group (next coll))))
(if (seq curr)
(conj res curr)
res))))
在repl中:
user> (map (partial group-loop 2)
[[]
nil
[1 2 3 1 2 3]
[1 2 3 1 2 3 2]
[2 1 2 3 1 2 3]
[1 3 4 1 3 4]])
;;([] []
;; [[1 2] [3 1 2] [3]]
;; [[1 2] [3 1 2] [3 2]]
;; [[2] [1 2] [3 1 2] [3]]
;; [[1 3 4 1 3 4]])
虽然它看起来有点过于冗长,但它仍然有一些相当重要的优点:首先它有点经典(我找到一个专业而不是骗局),第二:它很快(根据我的基准约3)比reduce
变体快一倍,比partition
变种快6到10倍
你也可以通过一些小的调整使它变得更加狡猾,像clojure的序列操作函数那样返回懒惰的集合:
(defn group-lazy [delim coll]
(loop [curr [] coll coll]
(if (seq coll)
(let [curr (conj curr (first coll))]
(if (= delim (first coll))
(cons curr (lazy-seq (group-lazy delim (rest coll))))
(recur curr (next coll))))
(when (seq curr) [curr]))))
user> (map (partial group-lazy 2)
[[]
nil
[1 2 3 1 2 3]
[1 2 3 1 2 3 2]
[2 1 2 3 1 2 3]
[1 3 4 1 3 4]])
;;(nil nil
;; ([1 2] [3 1 2] [3])
;; ([1 2] [3 1 2] [3 2])
;; ([2] [1 2] [3 1 2] [3])
;; [[1 3 4 1 3 4]])
答案 1 :(得分:1)
这是通过组合两个partition
变体的一种方式。首先使用partition-by
除以2的实例,然后使用partition-all
将这些分区中的两个和两个分开,并使用concat
将它们连接在一起。
(->> [0 1 2 0 1 2 0 1]
(partition-by (partial = 2)) ;;((0 1) (2) (0 1) (2) (0 1))
(partition-all 2) ;;(((0 1) (2)) ((0 1) (2)) ((0 1)))
(mapv (comp vec (partial reduce concat)))) ;;[[0 1 2] [0 1 2] [0 1]]
虽然请注意,如果输入从2开始,则返回的分区也将以2开始,而不是像这里那样结束。
答案 2 :(得分:0)
在这里,按照所有输入的要求工作:
reduce
虽然Magos有一个优雅的解决方案,但遗憾的是,他提到的并不完整。因此,上述内容应该使用2
来完成工作。
我们看一下最近添加的元素。如果是(conj %1 [%2])
,我们会创建一个新的子向量(partition
)。否则,我们将它添加到最后一个子矢量。真的很简单。像split
和fullscreenPlayPauseButton.style.backgroundImage = "url('../images/pause.png')";
这样的现有函数非常适合在可能的情况下重用,但有时最好的解决方案是自定义函数,在这种情况下它实际上非常干净。