【问题标题】:How to use an iterator in this case?在这种情况下如何使用迭代器?
【发布时间】:2011-04-16 14:50:55
【问题描述】:

我必须以这种方式遍历数组列表。

ArrayList<Integer> li = new ArrayList<Integer>();
li.add(20);
li.add(30);
li.add(40);
li.add(50);
li.add(70);

for (int i = 0; i < li.size() - 1; i++)
    System.out.println(li.get(i) + " " + li.get(i + 1));

输出:

20 30
30 40
40 50
50 70

如何使用迭代器做同样的事情?

【问题讨论】:

    标签: java iterator arraylist


    【解决方案1】:

    有点复杂:

    Iterator<Integer> iter = li.iterator();
    if (iter.hasNext()) {
        for (int y = iter.next(), x; iter.hasNext(); y = x) {
            x = iter.next();
            System.out.println(y + " " + x);
        }
    }
    

    或:

    if (iter.hasNext()) {
        for (int x = iter.next(); iter.hasNext();) {
            System.out.println(x + " " + (x = iter.next()));
        }
    }
    

    【讨论】:

    • 如果没有 hasNext() 检查,如果列表包含奇数个项目,您的 .next() 调用可能会抛出 NoSuchElementException。 download.oracle.com/javase/1.4.2/docs/api/java/util/…
    • 这假定迭代器中的项目数总是偶数
    • 在每个 next() 调用之前一个 hasNext() 检查。这两个选项都适用于任意数量的条目(0、1、2、3、4、5、6、7,...)。好吧,如果您不相信我,请自己尝试一下。
    • 第二个有点冒险,因为它依赖于从左到右的评估顺序才能使字符串连接正常工作...我知道 Java 规范保证了这一点,但仍然不推荐练习 (java.sun.com/docs/books/jls/second_edition/html/…)
    【解决方案2】:

    使用两个迭代器。我对此进行了测试,它对我有用。

        Iterator<Integer> first = li.listIterator();
    
        // Will raise IndexOutOfBoundsException if list is empty.
        Iterator<Integer> second = li.listIterator(1);
    
        while (second.hasNext()) {
            System.out.println(first.next() + " " + second.next());
        }
    

    编辑:不需要内部if。傻我。

    解释:listIterator(index) 方法返回一个从列表中指定位置开始的迭代器,而listIterator() 返回一个从零位置开始的迭代器。

    因此,first 迭代器从 0 开始,second1 开始。那么这只是在两者上打印next() 的问题。无论列表中的元素数是奇数还是偶数,这都会起作用。

    编辑 2

    我今天的逻辑很弱。感谢@barjak 指出空列表和不必要的first.hasNext() 的情况。

    【讨论】:

    • 1) 如果列表为空,此代码将不起作用。 2) first.hasNext() 没用,可以去掉。 3) 需要注意的重要一点是对next() 的两次调用是必要的,即使返回的值没有被使用。
    【解决方案3】:

    稍微修改了 Sagar V 的解决方案以使其工作。一个迭代器就足以实现这一点。

    Iterator iter = li.iterator();
            Integer int1 = null;
    
            while (iter.hasNext()) {
                if (int1 == null) {
                    int1 = (Integer) iter.next();
                }
    
                System.out.print(int1 + " ");
                if (iter.hasNext()) {
                    Integer int2 = (Integer) iter.next();
                    System.out.println(int2);
                    int1 = int2;
                } else {
                    break;
                }
            }
        }
    

    【讨论】:

      【解决方案4】:

      有很多解决方案,可以根据您的需要进行适当的调整。

      解决方案 1:固定大小的视图

      迭代列表子集的经典方法是创建原始列表的更窄视图,然后迭代整个视图。 subList 方法用于创建这样的视图。

      List<Integer> l = // initialization code
      
      int limitIndex = Math.max(l.size()-1, 0); // needed for empty list
      for (int v : l.subList(0, limitIndex)) {
          // your code
      }
      

      请注意,我使用了“foreach”循环,这是使用迭代器的便捷方式。这完全等同于这段代码:

      Iterator<Integer> it = l.subList(0, limitIndex).iterator();
      while(it.hasNext()) {
          int v = it.next();
          // your code
      }
      

      另外,请注意subList 方法不会创建新列表:它只会在原始列表上创建一个“视图”。原始列表的内容不会被复制,对原始列表所做的所有更改都可以从subList 创建的列表中看到。

      解决方案 2:自定义 Iterator/Iterable

      如果您只需要一个始终从 0 迭代到 n-1 的迭代器,您可以定义一个新的 Iterable 来满足该特定需求。

      public class NoLastIterable<T> implements Iterable<T> {
      
          private final List<T> backend;
      
          public NoLastIterable(List<T> backend) {
              this.backend = backend;
          }
      
          public Iterator<T> iterator() {
              return new Iterator<T>() {
      
                  private int nextIndex;
      
                  public boolean hasNext() {
                      return nextIndex < backend.size() -1;
                  }
      
                  public T next() {
                      return backend.get(nextIndex++);
                  }
      
                  public void remove() {
                      throw new UnsupportedOperationException("not implemented");
                  }
      
              };
          }
      }
      

      这个类是这样使用的:

      for (int v : new NoLastIterable<Integer>(l)) {
          // your code
      }
      

      解决方案 3

      您甚至可以创建 List 的自定义视图,就像 subList 所做的那样,但更灵活。

      public class NoLastList<T> extends AbstractList<T> {
      
          private final List<T> backend;
      
          public NoLastList(List<T> backend) {
              this.backend = backend;
          }
      
          @Override
          public T get(int index) {
              if (index >= size()) {
                  throw new IndexOutOfBoundsException();
              }
              return backend.get(index);
          }
      
          @Override
          public int size() {
              return Math.max(0, backend.size()-1);
          }
      
      }
      

      与其他解决方案的用法相同:

      for (int v : new NoLastList<Integer>(l)) {
          // your code
      }
      

      这种解决方案的好处体现在以下情况:

      1. 原始列表已创建并初始化
      2. NoLastList 实例已创建(作为原始列表的视图)
      3. 一些元素被添加到原始列表中

      在这种情况下,迭代 NoLastList 将考虑最近添加的元素。 NoLastList 始终表示从 0 到 n-1 的元素的视图,即使 n(大小)发生变化。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-01-27
        • 2022-01-23
        • 2015-11-30
        • 2017-05-16
        • 2012-10-06
        • 2011-05-18
        • 2019-11-29
        • 2022-01-23
        相关资源
        最近更新 更多