【问题标题】:Custom Iterator and method chaining in JavaJava中的自定义迭代器和方法链
【发布时间】:2020-05-16 13:14:28
【问题描述】:

我的自定义迭代器有问题,所以我寻求您的帮助。我有 MyIterator 类,它是一个带有转换的迭代器。这个类有方法:

  • next() - 返回下一个元素
  • hasNext() - 检查下一个元素是否存在
  • fromIterator - 静态方法,将 Iterator 转换为 MyIterator
  • map - 采用函数式接口并返回 MyIterator 以及对应于该接口的转换规则的方法
  • forEach - 采用功能接口并根据接口迭代所有剩余对象的方法。

    我的实现是

    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());
            }
        }
    }

所以,我做了这个任务,但我不明白,如何将方法 map 更改为链接方法(管道)。我的意思是:


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

例如,我有字符串“England”。在第一张地图之后,我想得到 7(“England”由 7 个字符组成),而不是“7”,而不是 1(因为字符串“7”由 1 个字符组成)。
我的假设是我应该在我的方法映射中使用方法 andThen/compose,但我不明白如何。

【问题讨论】:

  • 首先,您的map 方法将函数作为您完全忽略的参数。
  • 为什么你认为迭代器需要两个泛型类型参数? K 和 V 传统上代表“键”和“值”。在这种情况下,它们没有意义。这个k -&gt; (V) k 应该作为一个线索,表明你正在做的事情没有多大意义
  • @Michael,谢谢你的回答!我使用两个泛型类型参数,否则我将无法将 Function 作为我的类的一个字段。您还写了忽略函数的 map 方法,我理解,但除此之外我不知道如何使用此函数:return new MyIterator(它是必要的)与函数字段,其中函数看起来像 f1 .compose(f2).compose(f3)。等等,取决于在这个 MyIterator 对象上调用 .map 的次数。反正我是真的不知道怎么弄。那么,对吗?
  • 何不试试看?
  • @Michael,我试过了,还是不行,因为方法andThen需要Function,所以不能只写return new MyIterator(this.iterator, this.function.andThen(function));。因此,这种方法是不正确的或者我不明白这个功能是如何工作的

标签: java


【解决方案1】:

由于Iterator 接受一个参数,因此我修改了您的代码。

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());
      }
    }
 }

使用示例

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());

我希望这会有所帮助:)

【讨论】:

  • 谢谢你,清醒!非常优雅简洁的解决方案!它有帮助:)
【解决方案2】:

更新您的自定义迭代器并允许 fromIterator() 使用函数而不是您定义它


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());
        }
    }
}

,主要


    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);
    }

,输出

1
1
1
1

【讨论】:

  • 感谢您的回答,但它不像我要求的那样工作。我想获得链接逻辑,.map(s -&gt; s.length()).map(i -&gt; Integer.toString(i)).map(s -&gt; s.length())。所以,对于 "aaa",结果应该是 1 ("aaa"->3->"3"->1)
  • 理解你的想法,它行得通!非常感谢:D,另外,我可以问一个问题:是否可以像我上面提到的那样做(使用andThencompose,没有 List 字段或者我错了?
  • 我已经测试了上面的代码并且可以编译。它正在将上一个结果 R 构建为下一张地图中的 K 的地图
  • 以上代码,比较简单,我没试过compose/then你可以试试
  • 当然,抱歉,错过了。这是一个很好的决定,感谢您的帮助和解释,sc0der!你能回答我最后一个评论中的最后一个问题吗?你显然有更多的经验,我会很感激你! :)
猜你喜欢
  • 2021-02-27
  • 2020-04-21
  • 2016-07-10
  • 2017-07-25
  • 2013-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-05
相关资源
最近更新 更多