Reputation: 23
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
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
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