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
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.
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( ).
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.
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.
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.
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.]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With