是否有Java等效的Python'枚举'函数?

Ric*_*arn 70 python java iterator

在Python中,该enumerate函数允许您迭代一系列(索引,值)对.例如:

>>> numbers = ["zero", "one", "two"]
>>> for i, s in enumerate(numbers):
...     print i, s
... 
0 zero
1 one
2 two
Run Code Online (Sandbox Code Playgroud)

有没有办法在Java中这样做?

Ric*_*arn 54

对于实现该List接口的集合,您可以调用该listIterator()方法来获取ListIterator.迭代器(以及其他)有两种方法 - nextIndex()来获取索引; 并next()获取值(与其他迭代器一样).

所以上面的Python的Java等价物可能是:

List<String> numbers = Arrays.asList("zero", "one", "two");
ListIterator<String> it = numbers.listIterator();
while (it.hasNext()) {
    System.out.println(it.nextIndex() + " " + it.next());
}
Run Code Online (Sandbox Code Playgroud)

像Python一样输出:

0 zero
1 one
2 two
Run Code Online (Sandbox Code Playgroud)

  • 这是*替代*.`enumerate`的工作方式完全不同.python的`enumerate`将独立于其内部索引状态索引任意序列.它产生一个'替换'可迭代序列,其中(索引,元素)对作为元素.它接受一个`start`参数,它为索引添加一个偏移量 - 可以在循环中完成但仍然可以.它本身与for-each like循环一起工作. (7认同)
  • 正如@JB Nizet所说,是的,`next()`具有推进迭代器一个元素的副作用.但是Java语言规范保证了`+`运算符的操作数从左到右进行计算.见[第15.7节](http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#4779). (4认同)
  • 那么`it.next()`有副作用吗?在同一个表达式中混合使用`it.nextIndex()`和`it.next()`是否安全? (3认同)
  • 是的,它转到下一个元素。有关ListIterator的工作方式,请参见http://download.oracle.com/javase/6/docs/api/java/util/ListIterator.html。 (2认同)

Pac*_*ace 14

我发现这与python方法最相似.

用法

public static void main(String [] args) {
    List<String> strings = Arrays.asList("zero", "one", "two");
    for(EnumeratedItem<String> stringItem : ListUtils.enumerate(strings)) {
        System.out.println(stringItem.index + " " + stringItem.item);
    }
    System.out.println();
    for(EnumeratedItem<String> stringItem : ListUtils.enumerate(strings, 3)) {
        System.out.println(stringItem.index + " " + stringItem.item);
    }
}
Run Code Online (Sandbox Code Playgroud)

产量

0 zero
1 one
2 two

3 zero
4 one
5 two
Run Code Online (Sandbox Code Playgroud)

特征

  • 适用于任何可迭代的
  • 不创建内存列表副本(适用于大型列表)
  • 支持每种语法的原生
  • 接受可以添加到索引的start参数

履行

import java.util.Iterator;

public class ListUtils {

    public static class EnumeratedItem<T> {
        public T item;
        public int index;

        private EnumeratedItem(T item, int index) {
            this.item = item;
            this.index = index;
        }
    }

    private static class ListEnumerator<T> implements Iterable<EnumeratedItem<T>> {

        private Iterable<T> target;
        private int start;

        public ListEnumerator(Iterable<T> target, int start) {
            this.target = target;
            this.start = start;
        }

        @Override
        public Iterator<EnumeratedItem<T>> iterator() {
            final Iterator<T> targetIterator = target.iterator();
            return new Iterator<EnumeratedItem<T>>() {

                int index = start;

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

                @Override
                public EnumeratedItem<T> next() {
                    EnumeratedItem<T> nextIndexedItem = new EnumeratedItem<T>(targetIterator.next(), index);
                    index++;
                    return nextIndexedItem;
                }

            };
        }

    }

    public static <T> Iterable<EnumeratedItem<T>> enumerate(Iterable<T> iterable, int start) {
        return new ListEnumerator<T>(iterable, start);
    }

    public static <T> Iterable<EnumeratedItem<T>> enumerate(Iterable<T> iterable) {
        return enumerate(iterable, 0);
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 我只是在考虑实施这种事情。我认为这是标准库的一个很好的候选者。 (2认同)

Ada*_*kin 8

严格地说,不,因为Python中的enumerate()函数返回元组列表,而Java中不存在元组.

但是,如果您感兴趣的是打印索引和值,那么您可以按照Richard Fearn的建议并在迭代器上使用nextIndex()和next().

还要注意,可以使用更通用的zip()函数(使用Python语法)定义enumerate():

mylist = list("abcd")
zip(range(len(mylist)), mylist)
Run Code Online (Sandbox Code Playgroud)

给[(0,'a'),(1,'b'),(2,'c'),(3,'d')]

如果您定义自己的Tuple类(请参阅在Java中使用Pairs或2-tuples作为起点),那么您当然可以轻松地在Java中编写自己的zip()函数来使用它(使用在中定义的Tuple类)链接):

public static <X,Y> List<Tuple<X,Y>> zip(List<X> list_a, List<Y> list_b) {
    Iterator<X> xiter = list_a.iterator();
    Iterator<Y> yiter = list_b.iterator();

    List<Tuple<X,Y>> result = new LinkedList<Tuple<X,Y>>();

    while (xiter.hasNext() && yiter.hasNext()) {
        result.add(new Tuple<X,Y>(xiter.next(), yiter.next()));
    }

    return result;
}
Run Code Online (Sandbox Code Playgroud)

一旦你有zip(),实现enumerate()是微不足道的.

编辑:工作缓慢的一天,所以完成它:

public static <X> List<Tuple<Integer,X>> enumerate (List<X> list_in) {
    List<Integer> nums = new ArrayList<Integer>(list_in.size());
    for (int x = 0; x < list_in.size(); x++) { 
        nums.add(Integer.valueOf(x));
    }

    return zip (nums, list_in);
}
Run Code Online (Sandbox Code Playgroud)

编辑2:正如对这个问题的评论所指出的,这并不完全等同.虽然它产生的值与Python的枚举值相同,但它并没有像Python的枚举那样以相同的生成方式实现.因此,对于大型馆藏,这种方法可能非常令人望而却步


Tra*_*vis 5

根据 Python 文档(此处),这是您可以使用 Java 获得的最接近的结果,并且不再冗长:

String[] numbers = {"zero", "one", "two"}
for (int i = 0; i < numbers.length; i++) // Note that length is a property of an array, not a function (hence the lack of () )
    System.out.println(i + " " + numbers[i]);
}
Run Code Online (Sandbox Code Playgroud)

如果您需要使用List该类...

List<String> numbers = Arrays.asList("zero", "one", "two");
for (int i = 0; i < numbers.size(); i++) {
    System.out.println(i + " " + numbers.get(i));
}
Run Code Online (Sandbox Code Playgroud)

*注意:如果您需要在遍历列表时修改列表,则需要使用 Iterator 对象,因为它能够修改列表而不会引发ConcurrentModificationException.


bal*_*lki 5

简单明了

public static <T> void enumerate(Iterable<T> iterable, java.util.function.ObjIntConsumer<T> consumer) {
    int i = 0;
    for(T object : iterable) {
        consumer.accept(object, i);
        i++;
    }
}
Run Code Online (Sandbox Code Playgroud)

示例用法:

void testEnumerate() {
    List<String> strings = Arrays.asList("foo", "bar", "baz");
    enumerate(strings, (str, i) -> {
        System.out.println(String.format("Index:%d String:%s", i, str));
    });
}
Run Code Online (Sandbox Code Playgroud)