1

I know that currently there are two approaches to loop over an List. But let's complicate it a bit more, consider:

  • You iterate over List<E> list.
  • You want to keep track of an int y on every iteration.
  • There exists a function process(E elem, int y) that processes an item.

Option 1:

for (int i = 0, y = 0; i < list.size(); i++, y++) {
    process(list.get(i), y);
}

which actually just is

for (int i = 0; i < list.size(); i++) {
    process(list.get(i), i);
}

Option 2:

int y = 0;
for (E elem : list) {
    process(elem, y);
    y++;
}

which can be rewritten to

int y = 0;
for (E elem : list) {
    process(elem, y++);
}

However why does the following not exist? What are the objections to it not existing?

Option 3:

for (int y = 0; E elem : list; y++) {
    process(elem, y);
}

Two arguments to have this construct:

  • Both foreach syntaxes are distinguishable
  • Many objects implement Iterable<E>, but have no for counterpart. This happens when an Iterable<E> has no order associated with it for example.
4

6 回答 6

3

这接近提议的变体 3:

int y = 0;
for (Iterator<E> it=list.iterator(); it.hasNext(); y++) {
   process(it.next(), y);
}

或者

Iterator<E> it=list.iterator();
for (int y = 0; it.hasNext(); y++) {
   process(it.next(), y);
}

或者

Iterator it;int y;
for (y = 0, it=list.iterator(); it.hasNext(); y++) {
    process(it.next(), y);
}
于 2013-07-23T14:04:48.873 回答
0

在像 Python 这样的语言中,这可以通过使用整数序列压缩来解决:

>>> a = ['a','b','c','d']
>>> for val,i in zip(a, range(len(a))):
...   print val, i
...
a 0
b 1
c 2
d 3

显然,Java 对这样的东西没有语法支持,但我确实认为有充分的理由避免list.get(i)在每次迭代中调用,尤其是获取特定值可能比迭代到下一个值要慢得多(例如,使用一个链表)。

我不喜欢在使用循环语法时偏离惯例,所以我不太热衷于将不同的变量放在测试中并增加正常 for 循环的部分(Alexei Kaigorodov 的解决方案看起来不错,但可能会让人们感到困惑不熟悉的人)。我通常首选的解决方案是在使用 for-each 循环时单独维护计数,这是 OP 的选项 2。

或者,您可以使用我的CountingIterable<>类,它提供计数和值。这在生产代码中是否是一个好主意还有待商榷,但这个问题启发了我写下它并将它贴在 Github 上

它是这样使用的:

for (Counted<E> v : counting(iterable)) {
    process(v.getValue(), v.getCount());
}

(在代码中,这是counting从类中静态导入的Counting

于 2013-07-23T14:16:42.613 回答
0

因为太过分了?在这种情况下y没有任何意义,并且代码可以很容易地重写,如您所示。

例如,如果您想要这种非标准行为,也许可以尝试查看 Scala 语言。您将能够在那里创建真正可怕的控制结构。

于 2013-07-23T13:28:18.813 回答
0

我相信这是一个基于意见的问题。只有语言设计者才能回答这个问题。

Iterator如果您愿意接受创建包装Iterator以使索引可用的新对象,则可以使用实用程序类在一定程度上改进语法。请参见下面的示例:

public static void main(String[] args) {
    List<String> list = Arrays.asList( new String[] {"item1", "item2", "item3"} );

    for (IndexIterator<String> it = IndexIterator.of(list.iterator()); it.hasNext();) {
        System.out.println( it.next() + " : " + it.index() );
    }
    // Prints:
    // item1 : 0
    // item2 : 1
    // item3 : 2
}

实用程序类IndexIterator如下:

public static class IndexIterator<T> implements Iterator<T> {
    private int index = -1;
    private Iterator<T> iterator;
    public IndexIterator(Iterator<T> it) {
        this.iterator = it;
    }

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

    @Override
    public T next() {
        index++;
        return iterator.next();
    }

    @Override
    public void remove() {
        iterator.remove();
    }

    public int index() {
        return this.index;
    }

    public static <T> IndexIterator<T> of(Iterator<T> it) {
        return new IndexIterator<T>(it);
    }
}
于 2013-07-23T14:44:06.267 回答
0

这个 :

for (int y = 0; E elem : list; y++) {
   process(elem, y);
}

可以这样写:

E elem;
for (int y = 0 ; y < list.size(); y++, elem = list.get(y)) {
    process(elem, y);
}

尽管elem在这种情况下变量的范围不同。因此,我认为没有明确需要第三个选项,同样,意见可能会有所不同。

于 2013-07-23T13:34:22.247 回答
-1

不是吗

nextIndex() 

你在找什么而不是 y?Ps 使用 ListIterator

编辑:这就是我在代码中的意思:

Iterator<E> it = list.iterator();
while (it.hasNext()){
    process(it.next(), it.previousIndex());
}
于 2013-07-23T13:29:43.180 回答