Clojure:实施一个;缩进;功能

Clojure:实施一个;缩进;功能,clojure,Clojure,我想实现一个函数,它是交织和插入的“混合体”,称为缩进 的确,当你写作的时候 (interleave [1 2 3] ["_" "*"]) 它回来了 (1 "_" 2 "*") 但是我想要 (1 "_" 2 "*" 3) 所以我写了一个函数来实现这个目标: (defn indent "Mix of clojure.core interleave and interpose functions. Indents the second collection in the first

我想实现一个函数,它是
交织
插入
的“混合体”,称为
缩进

的确,当你写作的时候

(interleave [1 2 3] ["_" "*"])
它回来了

(1 "_" 2 "*")
但是我想要

(1 "_" 2 "*" 3)
所以我写了一个函数来实现这个目标:

(defn indent
  "Mix of clojure.core interleave and interpose functions.
   Indents the second collection in the first one."
  [coll1 coll2]
  (let [n1 (count coll1)
        n2 (count coll2)
        vcoll1 (vec coll1)
        vcoll2 (vec coll2)
        stop-idx (min (- n1 2) (- n2 1))]
    (-> (loop [init '()
               i 0]
          (cond (> i stop-idx)
                  init
                :else
                  (recur (concat init [(vcoll1 i) (vcoll2 i)]) (inc i))))
        (concat [(vcoll1 (inc stop-idx))]))))
问题是性能太差了:

(time (dotimes [_ 10000000] (doall f [1 2 3] ["_" "*"])))
对于f=交织:2秒 对于f=缩进:7秒

我试图模仿
interleave
impl,但最后我使用了相同的代价运算(count和vec)

我能看到的关于快速计算的唯一想法是编写Java代码

有什么想法吗?谢谢

编辑:更快的java方式

这不是Clojure解决方案,但它减少了计算时间

package java_utils;

public class Clojure {

    public static Object[] indent (Object[] coll1 , Object [] coll2) {

        int len1 = coll1.length;
        int len2 = coll2.length;

    int stop_index = Math.min(len1 - 2, len2 - 1);

    Object[] result = new Object[2*(stop_index+1) + 1];

    for (int i = 0 ; i <= stop_index ; i++) {
        result[2*i] = coll1[i];
        result[2*i+1] = coll2[i];
    }

    result[2*stop_index+2] = coll1[stop_index+1];

    return result;
}

对于10万次迭代,它的计算速度为1,7秒。

这些问题通常最好在Clojure中通过创建一个seq来解决。通常,seq需要更少的逻辑来实现,而且它们也很适合Clojure库

(defn interdent 
  ([seq1 seq2]
   (if (seq seq1)
     (lazy-seq
      (cons (first seq1) (interdent seq2 (rest seq1)))))))
还有,我不太确定你的时间代码。不确定你的例子中f是什么。用所讨论的函数替换f会产生错误。e、 g

user=> (time (dotimes [_ 10000000] (doall interpose [1 2 3] ["_" "*"])))

ArityException Wrong number of args (3) passed to: core/doall  clojure.lang.AFn.throwArity (AFn.java:429)
我使用下面的代码片段来计时代码

user=> (time (dotimes [_ 10000000] (doall (interpose [1 2 3] ["_" "*"]))))
e、 g


你为什么不把它建立在交织的基础上呢?像这样:

(defn indent2 [coll1 coll2]
  (when (seq coll1)
    (cons (first coll1)
          (interleave coll2 (rest coll1)))))

它的性能应该几乎等同于交织。

第一个序列总是比第二个序列长吗?或者这种行为类似于您正在寻找的
(最后一次拖放(交错[1 2 3 4](循环[“”“*”]))
?没有约束,因此也没有约束。如果有(缩进[1 2 3][“”“*”#“@“]),则将有(1“2”*“3”)等。结果类似于interleve,但最后一项始终位于左侧集合中。我们删除了不合适的数据。感谢您的回答,但行为不是预期的,最后一项应该属于集合1。它工作正常,我甚至没有想到!谢谢它没有那么快(3.5秒对2秒,基本交织*10000000),但它是惯用的,还可以。我用一个快速朴素的java impl编辑了我的文章,但最好还是坚持使用clojure,因为速度并不是那么重要
user=> (interdent [1 2 3] ["_" "*"])
(1 "_" 2 "*" 3)
user=> (interdent [1 2 3] ["_" "*" ":("])
(1 "_" 2 "*" 3 ":(")
user=> (interdent [1 2 3] ["_" "*" ":)" ":("])
(1 "_" 2 "*" 3 ":)")
(defn indent2 [coll1 coll2]
  (when (seq coll1)
    (cons (first coll1)
          (interleave coll2 (rest coll1)))))