是否有一种惯用的方式可以从这里出发:
[{:red 1} {:red 2} {:blue 3} {:blue 4} {:red 5} {:blue 6} {:red 7} {:red 8} {:red 9}]
到这里:
[[{:red 1} {:red 2}]
[{:blue 3}]
[{:blue 4}]
[{:red 5}]
[{:blue 6}]
[{:red 7} {:red 8} {:red 9}]]
即任何连续的红色都分组在一起,但是每个蓝色都作为一个单独的组保留吗?
谢谢。
答案 0 :(得分:2)
您可以使用partition-by
将序列中的连续值分组:
(partition-by ffirst [{:red 1} {:red 2} {:blue 3} {:blue 4} {:red 5} {:blue 6} {:red 7} {:red 8} {:red 9}])
;; => (({:red 1} {:red 2})
;; ({:blue 3} {:blue 4})
;; ({:red 5})
;; ({:blue 6})
;; ({:red 7} {:red 8} {:red 9}))
我发现在您的情况下,您只希望对:red
键进行分组。因此,我们可以为此构建特定的功能:
(partition-by #(or (contains? % :red) %)
[{:red 1} {:red 2} {:blue 3} {:blue 4} {:red 5} {:blue 6} {:red 7} {:red 8} {:red 9}])
;; => (({:red 1} {:red 2})
;; ({:blue 3})
;; ({:blue 4})
;; ({:red 5})
;; ({:blue 6})
;; ({:red 7} {:red 8} {:red 9}))
答案 1 :(得分:0)
以下是一种简单的方法:
(def x [{:red 1} {:red 2} {:blue 3} {:blue 4} {:red 5} {:blue 6} {:red 7} {:red 8} {:red 9}])
(partition-by #(if (:red %) :const (rand)) x)
;; =>(({:red 1} {:red 2})
;; ({:blue 3})
;; ({:blue 4})
;; ({:red 5})
;; ({:blue 6})
;; ({:red 7} {:red 8} {:red 9}))
partition-by
的作用是在集合的每个元素上运行一个函数,当我们获得不同的值时将其拆分。在这种情况下,我们需要构造一个自定义函数,该函数基于地图的键是:red
还是其他值(例如:blue
)进行分支,并始终为:red
返回相同的值(例如常数,例如关键字:const
),但始终为:blue
之类的其他键返回不同的东西(可以通过rand
之类的随机函数来完成)。
我们为它提供的匿名函数#(if (:red %) :const (rand))
就是这样做的-检查密钥是否为:red
,然后根据该密钥发出分支返回值。
但是,正如@cfrick在评论中提到的那样,担心连续两次获得相同的随机数-极不可能,但仍然令人担忧。如果使用rand
会使您感到有些不满意,则可以使用以下替代方法:使用当前时间(低至纳秒)而不是随机数,这样可以保证在顺序过程中始终能得到不同的结果:>
(partition-by #(if (:red %) :const (java.time.LocalDateTime/now)) x)
答案 2 :(得分:0)
先做一些工作然后再部分撤消可能有点笨拙,但是
在边界情况下至少相对安全(:blue
的值相同)
并实际上将任何非红色分开。
user=> (sequence
(comp
(partition-by #(contains? % :red))
(mapcat #(if (-> % first (contains? :red))
[%]
(map vector %))))
[{:red 1} {:red 2} {:blue 3} {:blue 3} {:red 5}])
([{:red 1} {:red 2}]
[{:blue 3}]
[{:blue 3}]
[{:red 5}])
答案 3 :(得分:0)
我会选择这样的东西:
(let [is-red? #(contains? % :red)]
(transduce (comp (partition-by is-red?)
(map #(if (is-red? (first %)) [%] (map vector %))))
into [] data))
;; [[{:red 1} {:red 2}]
;; [{:blue 3}]
;; [{:blue 4}]
;; [{:red 5}]
;; [{:blue 6}]
;; [{:red 7} {:red 8} {:red 9}]]
另一种方法是为blue
数据引入一些合成密钥,在这种情况下,index
可以:
(->> data
(map-indexed (fn [idx itm] {:key (or (contains? itm :red) idx)
:itm itm}))
(partition-by :key)
(map (partial map :itm)))
;; (({:red 1} {:red 2})
;; ({:blue 3})
;; ({:blue 4})
;; ({:red 5})
;; ({:blue 6})
;; ({:red 7} {:red 8} {:red 9}))
您还可以将分区键放在元数据中,以避免创建额外的记录:
(->> data
(map-indexed (fn [idx itm]
(vary-meta itm assoc :part-key (or (contains? itm :red) idx))))
(partition-by (comp :part-key meta)))
;; (({:red 1} {:red 2})
;; ({:blue 3})
;; ({:blue 4})
;; ({:red 5})
;; ({:blue 6})
;; ({:red 7} {:red 8} {:red 9}))
答案 4 :(得分:0)
(reduce
(fn [acc e]
(if (and (:red e) (:red (peek (peek acc))))
(update acc (dec (count acc)) conj e)
(conj acc [e])))
[]
[{:red 1} {:red 2} {:blue 3} {:blue 4} {:red 5} {:blue 6} {:red 7} {:red 8} {:red 9}])
;; => [[{:red 1} {:red 2}]
;; [{:blue 3}]
;; [{:blue 4}]
;; [{:red 5}]
;; [{:blue 6}]
;; [{:red 7} {:red 8} {:red 9}]]