【问题标题】:How to iterate over alternative elements using an iterator?如何使用迭代器迭代替代元素?
【发布时间】:2018-05-14 12:05:11
【问题描述】:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
Iterator<Integer> it = list.iterator();
while (it.hasNext()) {
    System.out.println(it.next());
}

上面的代码将依次迭代 1 到 6。我们可以交替迭代同一个列表,以便在不更改 while 循环的情况下打印1, 3, 5

【问题讨论】:

  • 一种可能性是重新排列您的列表,或者在打印之前检查值 (if (x==1 || x==3 || x==6))。 (它没有回答你的问题,这似乎是不可能的)
  • 只是想知道:你为什么要问?你想在这里解决什么真正的问题?

标签: java iterator


【解决方案1】:

创建您自己的Iterator

class SkippingIterator<T> implements Iterator<T> {
    private List<T> list;
    private currentPosition;
    private int skipBy;
    public SkippingIterator(List<T> l) {
        this(l, 2);
    }
    public SkippingIterator(List<T> l, int skip) {
        this(l, skipBy, 0);
    }
    public SkippingIterator(List<T> l, int skip, int startPosition) {
        list = l;
        skipBy = skip;
        currentPosition = startPosition;
    }
    public boolean hasNext() {
        return currentPosition < list.size();
    }
    public T next() {
        T result = list.get(currentPosition);
        currentPosition += skip;
        return result;
    }
}

编写代码

List<Integer> list = Arrays.asList(1,2,3,4,5,6);
Iterator it = new SkippingIterator<>(list);
while(it.hasNext()){
    System.out.println(it.next());
}

【讨论】:

  • hasNext 方法不应该也像(currentPosition + skipBy) &lt;= list.size()那样使用skipyBy属性吗?
  • @OHGODSPIDERS 以及currentPosition 指向将输出的下一个项目,所以这就是有效的。既然你提到了它,也许添加一个startPosition 是有意义的,这样你也可以在开头跳过。
  • 哦,好的。没关系。我不知何故认为它指向最后一个输出的项目。
  • @daniu 谢谢 Daniu...我需要的完美解决方案。
  • @daniu 非常好,但我认为这在 java-8 中更容易实现,因为只有一个 tryAdvance 方法 IMO...stackoverflow.com/a/50331960/1059372,我仍然赞成
【解决方案2】:

您只想打印奇数?使用流过滤列表:

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
Iterator<Integer> it = list.stream().filter(x -> x % 2 == 1).iterator();
while (it.hasNext()) {
    System.out.println(it.next());
}

编辑:

如果您想获取所有其他元素,那么使用流将不太合适,但您仍然可以这样做:

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
int limit = list.size() / 2 - (1 - list.size() % 2);
Iterator<Integer> it = IntStream.iterate(0, x -> x + 2).limit(limit).map(list::get).iterator();
while (it.hasNext()) {
    System.out.println(it.next());
}

我推荐大牛的解决方案。

【讨论】:

  • 我什至不知道 Stream 有一个 iterator() 方法...整洁。
  • 我想打印替代元素而不是奇数。如果列表将为 List list = Arrays.asList(10,20,30,40,50,61);,您的代码会打印替代元素吗
  • @Sweeper 我真的很想发布类似的东西(你的第二种方法),但我认为这是自定义拆分器的工作......stackoverflow.com/a/50331960/1059372 仍然是 1+
【解决方案3】:

一个简单的机制是只使用列表项的索引:

IntStream.range(0, list.size())
    .filter(i -> i % 2 == 0)
    .mapToObj(list::get)
    .forEach(System.out::println);

如果您特别想要一个迭代器,只需调用 iterator() 而不是 forEach

【讨论】:

    【解决方案4】:

    是的,你可以。在 while 循环体中,检查迭代器是否有下一个元素,如果有,则再次推进迭代器。这将导致不打印偶数元素。

    List<Integer> list=Arrays.asList(1,2,3,4,5,6);
    Iterator it=list.iterator();
    while (it.hasNext()){
        System.out.println(it.next());
        if (it.hasNext()) {
            it.next();
        }
    }
    

    【讨论】:

    • 这改变了while循环。
    • @daniu 我认为 OP 的意思是不改变 while 循环的条件。也许我错了。
    • 这对我来说很奇怪。由于Iterator 是一个接口,实现OP 任务的更合适的方法是覆盖Iterator 方法。
    【解决方案5】:

    我认为 java-8 的做法是这样的:

    class Skipping extends AbstractSpliterator<Integer> {
    
        private List<Integer> list;
        private int index = 0;
    
        public Skipping(List<Integer> list) {
            super(list.size() / 2, 0);
            this.list = new ArrayList<>(list);
        }
    
        @Override
        public boolean tryAdvance(Consumer<? super Integer> action) {
            if (index != list.size()) {
                if (index % 2 == 0) {
                    action.accept(list.get(index++));
                }
                ++index;
                return true;
            }
            return false;
        }
    
    }
    

    及用法:

    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
    Iterator<Integer> iter = StreamSupport.stream(new Skipping(list), false).iterator();
    

    【讨论】:

    • 一个优雅的解决方案,除了删除部分,对于更大的集合,这可能会变得非常昂贵。也许宁愿使用递增计数器作为索引
    • @Lino 我还在考虑它......是的,我完全同意你的看法。我会编辑
    【解决方案6】:

    您可以创建一个包装已经存在的迭代器的迭代器实现:

    class IteratorWrapper<T> implements Iterator<T> {
        private final Iterator<? extends T> iterator;
    
        public IteratorWrapper(Iterator<? extends T> iterator){
            this.iterator = iterator;
        }
    
        public boolean hasNext(){
            return iterator.hasNext();
        }
    
        public T next(){
            final T next = iterator.next();
            if(iterator.hasNext()){
                iterator.next();
            }
            return next;
        }
    
        public void remove(){
            iterator.remove();
        }
    } 
    

    使您的代码如下:

    List<Integer> list = Arrays.asList(1,2,3,4,5,6);
    Iterator<Iterator> it = new IteratorWrapper<>(list.iterator());
    while(it.hasNext()){
        System.out.println(it.next());
    }
    

    【讨论】:

    • 这看起来像装饰器模式。我们为什么不重写 Iterator 方法呢?
    • 你可能并不总是知道迭代器的来源,因此不能直接覆盖现有的。例如。来自ArrayList 的迭代器可能与来自HashSet 的迭代器不同
    • 是的,但是对于一些具体的类和具体的实现,我们能够(提前)知道什么以及如何实现Iterator 接口。例如。 IteratorForDivisibleBySeven
    • @zlakad 当然,但我的方法是最通用的方法,当然,如果您知道自己使用该功能,您可能想要覆盖现有的 Iterator
    • 我同意,装饰器模式可以用于更通用的情况......不过,如果你想在 Collection 上使用多个迭代器,你可以使用 Iterator 的乘法实现。更重要的是,您可以使用策略模式。
    【解决方案7】:

    Iterator 实现,它包装了一个已经存在的迭代器。它为备用迭代器提供了hasNext() 方法的逻辑正确定义,因为hasNext() 方法只有在存在备用位置编号时才应返回true。

        import java.util.Iterator;
    
        public class AlternateIterator<T> implements Iterator<T>{
    
            private T next;
            private Iterator<T> it;
    
            public AlternateIterator(Iterator<T> it) {
                this.it = it;
                next = null;
            }
            // Logically hasNext() of this iterator should return true only if it has a valid alternate element present.
            @Override
            public boolean hasNext() {
                if(next != null) {
                    return true;
                }
                if(it.hasNext()) {
                    it.next();
                    if(it.hasNext()) {
                        next = it.next();
                        return true;
                    }
                }
                return false;
            }
    
            @Override
            public T next() {
                if(next != null) {
                    T temp = next;
                    next = null;
                    return temp;
                }
                else {
                    if(hasNext())
                        return next();
                    else
                        return null;
                }
            }
        }
    

    【讨论】:

      【解决方案8】:

      从任何底层迭代器创建您自己的自定义迭代器:

      class TwoStepsAtOnceIterator<E> implements Iterator<E> {
          private Iterator<E> internal;
          public TwoStepsAtOnceIterator(Iterator<E> it) {
            internal = it;
          }
          public boolean hasNext() {
            return internal.hasNext();
          }
          public E next() {
            // problem not specified when underlying sequence has odd number of elements
            internal.next();
            return internal.next();
          }
          public void remove() {
            throw new UnsupportedOperationException();
          }
      }
      

      【讨论】:

      • 如果内部迭代器有奇数个项目,这将在next() 中引发异常。
      • @daniu 当然,但在这种情况下应该实现哪种行为并没有明确说明,所以我决定让它抛出它的“自然”异常
      • 您可能希望将 remove 方法委托给底层迭代器。或者至少抛出一个异常
      • 您不必删除任何内容,只需将remove()-方法委托给internal-Iterator,或者,就像您现在所做的那样,抛出UnsupportedOperationException
      • @Jean-BaptisteYunès 没错,因为行为没有真正定义(应该删除第一个或第二个元素吗?)
      【解决方案9】:

      一个非常简单的代码是这样的:

      List<Integer> list = Arrays.asList(1,2,3,4,5,6);
      Iterator it = list.iterator();
      while(it.hasNext()){
         static int i=0;
          if(i%2==0){
          System.out.println(it.next());
           }
           i+=1;
      }
      

      【讨论】:

        猜你喜欢
        • 2021-11-21
        • 2021-11-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-11
        • 1970-01-01
        • 2023-02-22
        • 1970-01-01
        相关资源
        最近更新 更多