分组单词等

时间:2014-08-30 17:00:35

标签: clojure transformation keyword

我正在研究一个在实践中学习Clojure的项目。我做得很好,但有时我会卡住。这次我需要转换形式的序列:

[":keyword0" "word0" "word1" ":keyword1" "word2" "word3"]

成:

[[:keyword0 "word0" "word1"] [:keyword1 "word2" "word3"]]

我正在尝试至少两个小时,但我知道没有那么多Clojure函数可以用函数方式组合一些有用的东西来解决问题。

我认为这个转换应该包括一些分区,这是我的尝试:

(partition-by (fn [x] (.startsWith x ":")) *1)

但结果如下:

((":keyword0") ("word1" "word2") (":keyword1") ("word3" "word4"))

现在我应该再次对它进行分组......我怀疑我在这里做的是正确的事情......另外,我需要将字符串(只有以:开头的字符串)转换为关键字。我认为这种组合应该有效:

(keyword (subs ":keyword0" 1))

如何编写以最惯用的方式执行转换的函数?

4 个答案:

答案 0 :(得分:1)

那怎么样:

(defn group-that [ arg ]
  (if (not-empty arg)
    (loop [list arg, acc [], result []]
      (if (not-empty list)
        (if (.startsWith (first list) ":")
          (if (not-empty acc)
            (recur (rest list) (vector (first list)) (conj result acc))
            (recur (rest list) (vector (first list)) result))
          (recur (rest list) (conj acc (first list)) result))
        (conj result acc)
        ))))

在Seq上只需1次迭代,无需任何宏。

答案 1 :(得分:1)

以下是使用reduce

的高性能版本
(reduce (fn [acc next]
          (if (.startsWith next ":")
            (conj acc [(-> next (subs 1) keyword)])
            (conj (pop acc) (conj (peek acc)
                                  next))))
        [] data)

或者,您可以像这样扩展您的代码

(->> data
     (partition-by #(.startsWith % ":"))
     (partition 2)
     (map (fn [[[kw-str] strs]]
            (cons (-> kw-str
                      (subs 1)
                      keyword)
                  strs))))

答案 2 :(得分:0)

既然这个问题已经存在......这是我的最大努力:

(def data [":keyword0" "word0" "word1" ":keyword1" "word2" "word3"])

(->> data
     (partition-by (fn [x] (.startsWith x ":")))
     (partition 2)
     (map (fn [[[k] w]] (apply conj [(keyword (subs k 1))] w))))

我仍然在寻找更好的解决方案或批评这一点。

答案 3 :(得分:0)

首先,让我们构造一个将向量v分解为子向量的函数,在属性pred的所有位置都会出现中断。

(defn breakv-by [pred v]
  (let [break-points (filter identity (map-indexed (fn [n x] (when (pred x) n)) v))
        starts (cons 0 break-points)
        finishes (concat break-points [(count v)])]
    (mapv (partial subvec v) starts finishes)))

对于我们的情况,给出

(def data [":keyword0" "word0" "word1" ":keyword1" "word2" "word3"])

然后

(breakv-by #(= (first %) \:) data)

生成

[[] [":keyword0" "word0" "word1"] [":keyword1" "word2" "word3"]]

请注意,初始子矢量不同:

  • 它具有谓词所在的 no 元素。
  • 长度为零。

所有其他人

  • 从谓词所在的唯一元素开始,
  • 至少长度为1.

所以breakv-by使用

的数据正常运行
  • 不以破坏元素或
  • 开头
  • 有一系列破坏元素。

出于问题的目的,我们需要解决breakv-by产生的问题:

(let [pieces (breakv-by #(= (first %) \:) data)]
  (mapv
    #(update-in % [0] (fn [s] (keyword (subs s 1))))
    (rest pieces)))
;[[:keyword0 "word0" "word1"] [:keyword1 "word2" "word3"]]