首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在clojure中用分隔符拆分序列?

在clojure中用分隔符拆分序列?
EN

Stack Overflow用户
提问于 2017-03-19 01:05:45
回答 3查看 1.2K关注 0票数 4

假设我有一个在clojure中的序列

代码语言:javascript
复制
'(1 2 3 6 7 8)

我希望将其拆分,以便每当遇到可被3整除的元素时,列表就会分裂,因此结果如下

代码语言:javascript
复制
'((1 2) (3) (6 7 8))

(编辑:我真正需要的是

代码语言:javascript
复制
[[1 2] [3] [6 7 8]]

,但我也将接受序列版本:)

在clojure中,最好的方法是什么?

partition-by无济于事:

代码语言:javascript
复制
(partition-by #(= (rem % 3) 0) '(1 2 3 6 7 8))
; => ((1 2) (3 6) (7 8))

split-with已接近:

代码语言:javascript
复制
(split-with #(not (= (rem % 3) 0)) '(1 2 3 6 7 8))
; => [(1 2) (3 6 7 8)]
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-03-19 04:31:07

这是个有趣的问题。我最近将split-using添加到图佩洛图书馆中,这在这里似乎很合适。我在下面的代码中保留了spyx调试语句,这样您就可以看到事情是如何进展的:

代码语言:javascript
复制
(ns tst.clj.core
  (:use clojure.test tupelo.test)
  (:require
    [tupelo.core :as t]  ))
(t/refer-tupelo)

(defn start-segment? [vals]
  (zero? (rem (first vals) 3)))

(defn partition-using [pred vals-in]
  (loop [vals   vals-in
         result []]
    (if (empty? vals)
      result
      (t/spy-let [
          out-first               (take 1 vals)
          [out-rest unprocessed]  (split-using pred (spyx (next vals)))
          out-vals                (glue out-first out-rest)
          new-result              (append result out-vals)]
        (recur unprocessed new-result)))))

这给了我们如下的输出:

代码语言:javascript
复制
out-first => (1)
(next vals) => (2 3 6 7 8)
[out-rest unprocessed] => [[2] (3 6 7 8)]
out-vals => [1 2]
new-result => [[1 2]]
out-first => (3)
(next vals) => (6 7 8)
[out-rest unprocessed] => [[] [6 7 8]]
out-vals => [3]
new-result => [[1 2] [3]]
out-first => (6)
(next vals) => (7 8)
[out-rest unprocessed] => [[7 8] ()]
out-vals => [6 7 8]
new-result => [[1 2] [3] [6 7 8]]

(partition-using start-segment? [1 2 3 6 7 8]) => [[1 2] [3] [6 7 8]]

或者对于更大的输入向量:

代码语言:javascript
复制
(partition-using start-segment? [1 2 3 6 7 8 9 12 13 15 16 17 18 18 18 3 4 5])
   => [[1 2] [3] [6 7 8] [9] [12 13] [15 16 17] [18] [18] [18] [3 4 5]]

您还可以使用嵌套的loop/recur创建解决方案,但是已经在split-using函数中编写了该解决方案:

代码语言:javascript
复制
(defn split-using   
  "Splits a collection based on a predicate with a collection argument.
  Finds the first index N such that (pred (drop N coll)) is true. Returns a length-2 vector
  of [ (take N coll) (drop N coll) ]. If pred is never satisified, [ coll [] ] is returned."
  [pred coll]
  (loop [left  []
         right (vec coll)]
    (if (or (empty? right) ; don't call pred if no more data
            (pred right))
      [left right]
      (recur  (append left (first right))
              (rest right)))))

实际上,上面的函数似乎在将来是有用的。已经被添加了到图佩罗图书馆。

票数 2
EN

Stack Overflow用户

发布于 2017-03-19 03:58:01

像这样吗?

代码语言:javascript
复制
(defn partition-with
  [f coll]
  (lazy-seq
    (when-let [s (seq coll)]
      (let [run (cons (first s) (take-while (complement f) (next s)))]
        (cons run (partition-with f (seq (drop (count run) s))))))))

(partition-with #(= (rem % 3) 0) [1 2 3 6 7 8 9 12 13 15 16 17 18])
=> ((1 2) (3) (6 7 8) (9) (12 13) (15 16 17) (18))
票数 4
EN

Stack Overflow用户

发布于 2017-03-19 20:55:51

还有一个老派的基于缩减的解决方案:

代码语言:javascript
复制
user> (defn split-all [pred items]
        (when (seq items)
          (apply conj (reduce (fn [[acc curr] x]
                                (if (pred x)
                                  [(conj acc curr) [x]]
                                  [acc (conj curr x)]))
                              [[] []] items))))
#'user/split-all

user> (split-all #(zero? (rem % 3)) '(1 2 3 6 7 8 10 11 12))
;;=> [[1 2] [3] [6 7 8 10 11] [12]]
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42881750

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档