我正在研究一个在实践中学习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))
如何编写以最惯用的方式执行转换的函数?
答案 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"]]
请注意,初始子矢量不同:
所有其他人
所以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"]]