在clojure中使用更有效地拆分



Clojure的split-with函数非常方便,但必须遍历seq的前导部分两次,因为它实际上是作为[(take-while pred coll) (drop-while pred coll)]实现的。尽管如此,编写一个只遍历前导部分一次(将前导部分放入累积向量中,等等)的(尾部递归)版本还是相当容易的

然而,我想提取列表中满足谓词的第一个元素,并返回该元素和剩余列表(即(concat (take-while pred coll) (next (drop-while pred coll))))——希望在一次遍历中完成。如果我使用命令式语言,我只需遍历列表,抓住最后一个单元格,一旦我弹出元素,摆弄上一个单元格的"下一个指针"来重建修改后的列表,但这在函数式语言中似乎是不可能的。

那么,在Clojure中有没有一种方法可以有效地做到这一点呢?

对于split-with(以及希望从一个输入产生两个输出的类似任务),您可以使用任意两个

  • 懒惰
  • 不可变性
  • 完美的效率

例如,如果您不希望(第一个"丢弃"部分的)懒惰,您可以按照建议通过实现尾部递归版本来获得另外两个。

所有这些都不适用于您当前的问题,因为您只想要一个输出序列,我推荐kotarak的解决方案(或其他类似的解决方案)。但是,我想您可能想要解释一下为什么Clojure的内置split-with遍历输入序列两次。

对于特殊要求,您可以随时下拉到lazy-seq

(defn splice-tail
  ([pred coll] (splice-tail pred 1 coll))
  ([pred n coll]
   (lazy-seq
     (when-let [s (seq coll)]
       (let [fst (first s)]
         (if (pred fst)
           (cons fst (splice-tail pred n (rest s)))
           (nthnext s n)))))))

相关内容

  • 没有找到相关文章

最新更新