Danila
Danila

Reputation: 23

Custom Iterator and method chaining in Java

I have a problem with my custom iterator, so I'm asking for your help. I have class MyIterator, which is an iterator with transformation. This class has methods:


    import java.util.Iterator;
    import java.util.function.Consumer;
    import java.util.function.Function;

    public class MyIterator<K, V> {
        private final Iterator<K> iterator;
        private final Function<K, V> function;

        @SuppressWarnings("unchecked")
        public static <K, V> MyIterator<K, V> fromIterator(Iterator<K> iterator) {
            return new MyIterator<>(iterator, k -> (V) k);
        }

        private MyIterator(Iterator<K> iterator, Function<K, V> function) {
            this.iterator = iterator;
            this.function = function;
        }

        public V next() {
            return this.function.apply(iterator.next());
        }

        public boolean hasNext() {
            return this.iterator.hasNext();
        }

        public MyIterator<K, V> map(Function<K, V> function) {
            return new MyIterator<K, V>(this.iterator, this.function);
        }

        public void forEach(Consumer<V> action) {
            while (hasNext()) {
                action.accept(this.next());
            }
        }
    }

So, I did this task, but I can't understand, how to change the method map into chaining method (pipeline). I mean the following:


    MyIterator<String, Integer> myIterator3 = MyIterator.fromIterator(stringsArray.iterator()).map(s -> s.length()).map(i -> i.toString()).map(s -> s.length());

For example, I have String "England". After first map I want to get 7 ("England" consists of 7 characters), than "7", than 1 (because String "7" consists of 1 character).
My assumption is that I should use methods andThen/compose in my method map, by I can't understand, how.

Upvotes: 2

Views: 821

Answers (2)

lucid
lucid

Reputation: 2900

As Iterator accepts one parameter, here is how I modified your code.

public class ChainedIterator<T> {

    private Function<T, ?> action;

    private ChainedIterator<T> chain;

    private final Iterator<?> iterator;

    private <R> ChainedIterator(Iterator<?> iterator, Function<T, R> action, ChainedIterator<T> prev) {
      this.action = action;
      this.chain = prev;
      this.iterator = iterator;
    }

    public static <T> ChainedIterator<T> fromIterator(Iterator<T> iterator) {
      return new ChainedIterator<>(iterator, Function.identity(), null);
    }

    public T next() {
      return (T) this.action.apply((T) (Objects.nonNull(this.chain) ? this.chain.next() : this.iterator.next()));
    }

    public boolean hasNext() {
      return this.iterator.hasNext();
    }

    public <R> ChainedIterator<R> map(Function<T, R> action) {
      return new ChainedIterator(this.iterator, action, this);
    }

    public void forEach(Consumer<T> action) {
      while (hasNext()) {
        action.accept(this.next());
      }
    }
 }

Usage Example

Iterator<String> stringIterator = Arrays.asList("England", "India").iterator();

ChainedIterator<Integer> iterator = ChainedIterator.fromIterator(stringIterator)
  .map(s -> s.length())
  .map(i -> String.valueOf(i))
  .map(s -> s.length());

I hope this helps :)

Upvotes: 2

0xh3xa
0xh3xa

Reputation: 4857

Update your custom Iterator and allow fromIterator() takes function rather you define it


public class MyIterator<K, V> {

    private Iterator<K> iterator;
    private List<Function<K, ?>> functions;

    public static <K, V> MyIterator<K, V> fromIterator(Iterator<K> iterator) {
        return new MyIterator<>(iterator);
    }

    private MyIterator(Iterator<K> iterator) {
        this.iterator = iterator;
        functions = new ArrayList<>();
    }

    private MyIterator(Iterator<K> iterator, Function<K, ?> function) {
        this.iterator = iterator;
        functions = new ArrayList<>();
        functions.add(function);
    }

    private MyIterator(Iterator<K> iterator, List<Function<K, ?>> functions) {
        this.iterator = iterator;
        this.functions = functions;
    }

    public Object next() {
        K key = iterator.next();
        Object val = null;
        for (int i = 0; i < functions.size(); i++) {
            val = functions.get(i).apply(key);
            key = (K) val;
        }
        return val;
    }

    public boolean hasNext() {
        return iterator.hasNext();
    }

    public <R, RR> MyIterator<R, RR> map(Function<K, R> function) {
        List<Function<K, ?>> functions2 = this.functions;
        functions2.add(function);
        return new MyIterator(iterator, functions2);
    }

    public void forEach(Consumer<Object> action) {
        while (hasNext()) {
            action.accept(next());
        }
    }
}

, main


    public static void main(String[] args) throws Exception {
        Iterator<String> sIterator = Arrays.asList("aaa", "bbbb", "cccc", "ddddd").iterator();
        MyIterator.<String, Object>fromIterator(sIterator).map(s -> s.length()).map(i -> i + "")
                .map(str -> str.length()).forEach(System.out::println);
    }

, output

1
1
1
1

Upvotes: 2

Related Questions