2024 Clojure 状态调查!分享您的想法。

欢迎!请查看关于页面,了解更多关于如何使用本站的信息。

+1
Clojure
(let [coll [{:a 1 :b 2}
            {:a 3 :b 4}
            {:a 7 :b 5}
            {:a 1 :b 4}]
      xf1 (comp (map :a) (filter #{1 3}))
      xf2 (comp (map :b) (filter #{2 4}))]
  (concat
    (into [] xf1 coll)
    (into [] xf2 coll)))

有没有一种方法可以将上面两个 xform (xf1 和 xf2)合并成一个,使得集合 coll 只被遍历一次?

4 答案

0

这并不是转换器的组合,而是

(let [coll [{:a 1 :b 2}
            {:a 3 :b 4}
            {:a 7 :b 5}
            {:a 1 :b 4}]
      xf1 #(-> % :a #{1 3})
      xf2 #(-> % :b #{2 4})] 
  (into []
    (comp 
      (mapcat (juxt xf1 xf2))
      (remove nil?))
    coll))
=> [1 2 3 4 1 4]
尝试了,但我正在寻找一种组合转换器的方法...
0
  (let [coll [{:a 1 :b 2}
              {:a 3 :b 4}
              {:a 7 :b 5}
              {:a 1 :b 4}]
        xf1 (comp (map :a) (filter #{1 3}))
        xf2 (comp (map :b) (filter #{2 4}))]
    (eduction cat [(eduction xf1 coll) (eduction xf2 coll)]))

eduction 可以用 sequence 代替

0
by
(defn facet [m]
  (fn [f]
    (let [m (into {} (for [[k v] m]
                       [k (v f)]))]
      (fn
        ([accum]
         (reduce
          (fn [accum1 [k accum2]]
            (assoc accum1 k ((get m k) accum2)))
          accum
          accum))
        ([accum value]
         (reduce
          (fn [accum1 [k accum2]]
            (assoc accum1 k ((get m k) accum2 value)))
          accum
          accum))))))

(let [coll [{:a 1 :b 2}
            {:a 3 :b 4}
            {:a 7 :b 5}
            {:a 1 :b 4}]
      xf1 (comp (map :a) (filter #{1 3}))
      xf2 (comp (map :b) (filter #{2 4}))]
  ((comp (partial apply concat)
         (juxt :a :b))
   (transduce
    (facet {:a xf1
            :b xf1})
    conj
    {:a []
     :b []}
    coll)))
by
寻找有趣的转换器的良好地方是https://github.com/cgrand/xforms,不同种类的折叠处理的灵感来源则是https://github.com/aphyr/tesser
0
by
编辑了 by

哎呀,我意识到我实际上没有回答您的问题。我将我的原始回答移动到注释中。

使用cgrand/xforms,一个可能的答案是

(let [coll [{:a 1 :b 2}
            {:a 3 :b 4}
            {:a 7 :b 5}
            {:a 1 :b 4}]
      xf1 (comp (map :a) (filter #{1 3}))
      xf2 (comp (map :b) (filter #{2 4}))]
  (= (concat
      (into [] xf1 coll)
      (into [] xf2 coll))
     
     ;; do it in one pass
     (x/into []
       (comp (x/transjuxt [(comp xf1 (x/into [])) (comp xf2 (x/into []))])
             cat
             cat)
       coll)))
by
这里有一个搜索功能真是太好了。我最近遇到了类似的情况,我希望对几个输入集合执行不同的转换并最终获得一个集合,所以我尝试了几种不同的方法。

以下是我的REPL会话。在对criterium进行了一些基本的性能测试后,我得出结论,通过多个 `into` 线程集合的解决方案可能是最符合常规使用的,并且在性能上并不比 `catduce` 差。

    (def input1 (into [] (range 100000)))
    (def input2 (into [] (range 999 9999)))
    (def xf1 (filter odd?))
    (def xf2 (map inc))
    (def xf3 (take 100))
    (def xf4 (comp (filter even?) (map dec) (take 1000)))
  
    ;; concat (不希望它惰性操作并且分配了多个中间集合)
    (def result (into []
                            (concat
                                 xf1 input1)
                                 xf2 input1)
                                 xf3 input2)
                                 xf4 input2))))
  
    ;; cat (依然分配了中间集合)
    (= result
       (into []
               cat
              [(into [] xf1 input1)
              (into [] xf2 input1)
              (into [] xf3 input2)
              (into [] xf4 input2)]))
  
    ;; intos (没有中间分配,但有多处瞬时/持久的转换)
    ;; - 虽然如此,这仍然不是一个太大的问题,因为它们的操作都是 O(1))
    (= result
        (-> []
             (into xf1 input1)
             (into xf2 input1)
             (into xf3 input2)
             (into xf4 input2)))
  
    ;; reduce into
    ;; - 几乎与 intos 解决方案相同,无需多次写入 into)
    (= result
       (reduce
          #(into %1 (second %2) (first %2))
          []
          [[input1 xf1]
           [input1 xf2]
           [input2 xf3]
           [input2 xf4]]))
  
    ;; catduce
    ;; - 尝试在不进行多次瞬时/持久转换的情况下完成
    (defn catduce
      "借鉴自 clojure.core/cat"
       [rf]
      (fn
       [] []
       [result] (rf result))
       [result input+xf]
        (transduce (second input+xf) rf result (first input+xf)))))
  
    (= result
       (into [] catduce
              [[input1 xf1]
               [input1 xf2]
               [input2 xf3]
               [input2 xf4]]))
...