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

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

0
Clojure

take-nth transducer 在每个索引中调用模运算(rem),与使用零?测试相比,成本较高。由于步长是固定的,它可以直接从 N 计数。

5 答案

0

评论来自:[email protected]

附上补丁。在像 (time (transduce (take-nth 13) + (range 1e7))) 这样的简单测试中,它大约快 25%。

(time (transduce (take-nth 13) + (range 1e7)))

0

评论来自:[email protected]

我没有考虑 (take-nth 0) 的情况,但我的补丁确实得到一个不同的结果。当前实现得到一个除以零错误(来自 rem)。我的补丁版本只会一次返回第一个元素。常规集合版本会返回一个包含第一个元素的无限序列。我怀疑没有人期望从 0 的情况得到一个合理的答案,所以我也没有试图对它做任何特殊处理。

0

评论来自:michaelblume

很好 =)

我可以说,transducer 版本应该尽可能地与集合版本匹配,但我不认为实际上有办法编写一个可以将有限序列转换为无限序列的 transducer,所以在这方面没有运气。

也许我们在这个时候应该将 transducer 和集合的算子都改为在 0 时抛出异常?

0
评论由:reborg_ 提出

垃圾输入垃圾输出(GIGO) 案例中,但 rem 也是负责的


用户=> (take-nth 2.5 (range 10))
(0 3 6 9)
用户=> (sequence (take-nth 2.5) (range 10))
(0 5)


Steve 的补丁(CLJ-1665-faster-take-nth-transducer-without-rem.patch)中缺少一个 int 类型转换来解决上述问题


(defn take-nth [n]
  (fn [rf]
    (let [n (int n)
          iv (volatile! 1)]
      (fn
        ([] (rf))
        ([result] (rf result))
        ([result input]
         (let [i (vswap! iv dec)]
           (if (zero? i)
             (do (vreset! iv n)
                 (rf result input))
             result)))))))


0
参考:[https://clojure.atlassian.net/browse/CLJ-1665](https://clojure.atlassian.net/browse/CLJ-1665)(由 [email protected] 报告)
欢迎来到 Clojure Q&A,在这里您可以从 Clojure 社区成员那里提问并获得答案。
...