Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do turn a java Iterator-like object into a clojure sequence

I'm using the Sesame library to run SPARQL queries over an in-memory triple store.

I am using Clojure to achieve this.

A query result is a custom Iterator-like [1] object, so the clojure seq does not work on it out of the box.

What is the most elegant way to turn a custom java Iterator like object into a clojure sequence?

The most obvious and dumb idea that has come to my mind is to loop over it and build up a clojure vector, but I'm sure there is more elegant approach to this problem.

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

like image 483
laczoka Avatar asked Feb 10 '12 10:02

laczoka


People also ask

What is a clojure sequence?

Clojure defines many algorithms in terms of sequences (seqs). A seq is a logical list, and unlike most Lisps where the list is represented by a concrete, 2-slot structure, Clojure uses the ISeq interface to allow many data structures to provide access to their elements as sequences.

How do iterate an iterator?

Obtain an iterator to the start of the collection by calling the collection's iterator( ) method. Set up a loop that makes a call to hasNext( ). Have the loop iterate as long as hasNext( ) returns true. Within the loop, obtain each element by calling next( ).

What is universal iterator in Java?

An Iterator is an object that can be used to loop through collections, like ArrayList and HashSet. It is called an "iterator" because "iterating" is the technical term for looping. To use an Iterator, you must import it from the java. util package.

What are the methods of iterator in Java?

The Iterator interface of the Java collections framework allows us to access elements of a collection. It has a subinterface ListIterator . All the Java collections include an iterator() method. This method returns an instance of iterator used to iterate over elements of collections.


2 Answers

Pure functional iterable-to-lazy-sequence code for java Iterable and Iterator

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

For custom iterators replace .iterator, .hasNext and .next calls.

The advantage is that it's purely functional since it takes iterable as an argument. Other posted solutions take iterator argument which is mutable so the function may return a different sequence depending on internal iterator state what violates referential transparency. The function is also flamboyant about its laziness.

like image 168
Grzegorz Luczywo Avatar answered Oct 06 '22 13:10

Grzegorz Luczywo


How about wrapping the iterator-like object in an object that actually implements the Iterator interface? Something like the following (not tested):

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

As far as I can tell, the only advantage (if you want to call it that) of the Iteration interface over the standard Iterator interface is that it allows to declare checked exceptions, which are not used in Clojure anyways.

[Update: Corrected code to use iterator-seq instead of seq, as suggested by @amalloy in a comment on another answer.]

like image 27
Christian Berg Avatar answered Oct 06 '22 13:10

Christian Berg