Clojure序列中子序列的位置

6

Clojure中是否提供任何内置方式来查找给定序列中子序列的位置?

2个回答

7

Clojure提供了一种内置的简便方式,可轻松进行Java交互

(java.util.Collections/indexOfSubList '(a b c 5 6 :foo g h) '(5 6 :foo))
;=> 3

感谢您的回答。最终我会采用这种方式,但通常我会尽量避免在“业务”代码中明确调用Java互操作性,因为我觉得它有点冗长。不过还是非常感谢您的回答。 - Tudor Vintilescu
虽然这可能可行,但要注意集合不是序列。 - NielsK
@NielsK 除了哲学概念之外,我认为您会发现java.util.Listseq的超类,并且该Java方法与java.util.List成对出现。因此,您可以在惰性序列上使用它(只需小心不要评估无限序列)(java.util.Collections/indexOfSubList (range 10) (range 3 7)) ;=> 3,向量,排序映射等。 - A. Webb
这很有趣。然而,它似乎可以在惰性序列上工作,但操作本身似乎并不是惰性的。我在(range 10000000)(range 999998 999999)上尝试了两种方法,使用Collections方法时出现了GC开销限制,并且使用我的find-pos得到了正常答案。因此,必须有更多不仅仅是哲学概念的东西。 - NielsK
@NielsK 你是正确的。当你禁用GC开销检查时,它确实试图将整个范围实现到内存中。 - A. Webb

4
一个序列是一种抽象,而不是具体的实现。某些你可以通过序列抽象使用的具体实现(例如字符串和Java集合)有一种方法来找到一个子序列的位置,但是一般的序列没有这个功能,因为底层的具体实现不一定有索引。但是,你可以创建一个元素标识和索引函数的组合。请查看map-indexed。这里有一个简单的实现,它会惰性地查找序列中(所有)子序列的位置。只需使用first或take 1来查找一个即可。
(defn find-pos
  [sq sub]
  (->>
    (partition (count sub) 1 sq)
    (map-indexed vector)
    (filter #(= (second %) sub))
    (map first)))

=> (find-pos  [:a :b \c 5 6 :foo \g :h]
                [\c 5 6 :foo])
(2)

=> (find-pos  "the quick brown fox"
                (seq "quick"))
(4)

请注意,在函数式编程语言中通常不会使用基于索引的算法。除非在最终结果中需要索引有很好的理由,否则过度使用索引查找被认为是代码异味。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接