如何将类似java Iterator的对象转换为clojure序列

时间:2012-02-10 10:00:05

标签: java clojure seq sesame

我正在使用Sesame库在内存中的三重存储中运行SPARQL查询。

我正在使用Clojure来实现这一目标。

查询结果是一个类似自定义Iterator的[1]对象,因此clojure seq 无法开箱即用。

将自定义java Iterator类似对象转换为clojure序列的最优雅方法是什么?

我想到的最明显和最愚蠢的想法是循环它并构建一个clojure向量,但我确信有更优雅的方法解决这个问题。

[1] http://www.openrdf.org/doc/sesame2/api/info/aduna/iteration/Iteration.html

4 个答案:

答案 0 :(得分:10)

测试版本:

(defn iteration->seq [iteration]
 (seq
  (reify java.lang.Iterable 
      (iterator [this] 
         (reify java.util.Iterator
           (hasNext [this] (.hasNext iteration))
           (next [this] (.next iteration))
           (remove [this] (.remove iteration)))))))

答案 1 :(得分:7)

如何在实际实现Iterator接口的对象中包装类似迭代器的对象?类似于以下内容(未经测试):

(defn iteration-seq [iteration]
  (iterator-seq
   (reify java.util.Iterator
     (hasNext [this] (.hasNext iteration))
     (next [this] (.next iteration))
     (remove [this] (.remove iteration)))))

据我所知,Iteration接口上标准Iterator接口的唯一优势(如果你想称之为)是它允许声明已检查的异常,这是反正在Clojure中没有使用过。

[更新:更正了使用iterator-seq代替seq的代码,正如@amalloy在另一个答案的评论中所建议的那样。]

答案 2 :(得分:2)

为什么不试试clojure.core/iterator-seq

user=> (doc iterator-seq)
-------------------------
clojure.core/iterator-seq
([iter])
  Returns a seq on a java.util.Iterator. Note that most collections
  providing iterators implement Iterable and thus support seq directly.

正如您在上面的docstring中所看到的,您甚至可能不需要显式使用iterator-seq。您是否只是尝试将Java迭代器视为REPL中的序列?

答案 3 :(得分:1)

java Iterable和Iterator的纯函数可迭代到懒惰序列代码

(defn iter-seq
  ([iterable] 
    (iter-seq iterable (.iterator iterable)))
  ([iterable i] 
    (lazy-seq 
      (when (.hasNext i)
        (cons (.next i) (iter-seq iterable i))))))

对于自定义迭代器,替换.iterator,.hasNext和.next调用。

优点是它纯粹是功能性的,因为它需要迭代作为参数。其他发布的解决方案采用可变的迭代器参数,因此函数可能会返回不同的序列,具体取决于违反referential transparency的内部迭代器状态。 这个功能也很懒散。