有Python的“枚举”function的Java等价物吗?
在Python中, enumerate
函数允许您迭代(索引,值)对的序列。 例如:
>>> numbers = ["zero", "one", "two"] >>> for i, s in enumerate(numbers): ... print i, s ... 0 zero 1 one 2 two
有什么办法在Java中这样做?
对于实现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()); }
它像Python一样输出:
0 zero 1 one 2 two
严格来说,不,因为Python中的enumerate()函数返回元组列表,并且元组不在Java中存在。
然而,如果你感兴趣的是打印一个索引和一个值,那么你可以按照Richard Fearn的build议,在迭代器上使用nextIndex()和next()。
还要注意,可以使用更一般的zip()函数(使用Python语法)定义enumerate():
mylist = list("abcd") zip(range(len(mylist)), mylist)
给出[(0,'a'),(1,'b'),(2,'c'),(3,'d')]
如果你定义了你自己的Tuple类(参见在Java中使用Pairs或2-tuples作为起点),那么你当然可以用Java编写自己的zip()函数来使用它(使用链接):
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; }
一旦你有zip(),实现枚举()是微不足道的。
编辑:在工作缓慢的一天,所以完成它:
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); }
编辑2:正如在这个问题的评论中指出的,这不完全等同。 虽然它产生与Python枚举相同的值,但它并没有像Python枚举那样生成相同的生成方式。 因此,对于大型collections品来说,这种方法可能相当令人望而却步
我觉得这是最类似于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); } }
产量
0 zero 1 one 2 two 3 zero 4 one 5 two
特征
- 适用于任何迭代
- 不创build内存中列表副本(适用于大型列表)
- 支持每种语法的本机
- 接受可以添加到索引的开始参数
履行
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); } }
根据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]); }
如果你需要使用List
类…
List<String> numbers = Arrays.asList("zero", "one", "two"); for (int i = 0; i < numbers.size(); i++) { System.out.println(i + " " + numbers.get(i)); }
*注意:如果需要在遍历列表时修改列表,则需要使用Iterator对象,因为它能够在不引发ConcurrentModificationException
情况下修改列表。
List<String> list = { "foo", "bar", "foobar"}; int i = 0; for (String str : list){ System.out.println(i++ + str ); }
不,也许有一些库支持这样的function。 但是,如果你诉诸标准的图书馆,这是你的工作数。
我认为这应该是类似于Python“枚举”最多的Javafunction,虽然它是相当复杂和不足。 基本上,只需使用ListIterator或Collector将列表的索引映射到其元素:
List<String> list = new LinkedList<>(Arrays.asList("one", "two", "three", "four")); Map<Integer, String> enumeration = new Map<>(); ListIterator iter = list.listIterator(); while(iter.hasNext){ map.put(iter.nextIndex(), iter.next()); }
或使用lambdaexpression式:
Set<Integer, String> enumeration = IntStream.range(0, list.size()).boxed.collect(Collectors.toMap(index -> index, index -> list.get(index)));
那么你可以在增强的for循环中使用它:
for (Map.Entry<Integer, String> entry : enumeration.entrySet){ System.out.println(entry.getKey() + "\t" + entry.getValue()); }
现在将Java 8s Stream API与提供StreamUtils
的小型ProtonPack
库一起轻松实现。
第一个例子在问题中使用相同的每个符号:
Stream<String> numbers = Arrays.stream("zero one two".split(" ")); List<Indexed<String>> indexedNumbers = StreamUtils.zipWithIndex(numbers) .collect(Collectors.toList()); for (Indexed<String> indexed : indexedNumbers) { System.out.println(indexed.getIndex() + " " + indexed.getValue()); }
以上虽然不提供像Python一样的懒惰评估。 为此,您必须使用forEach()
Stream API方法:
Stream<String> numbers = Arrays.stream("zero one two".split(" ")); StreamUtils.zipWithIndex(numbers) .forEach(n -> System.out.println(n.getIndex() + " " + n.getValue()));
懒惰的评估可以通过以下无限stream来validation:
Stream<Integer> infStream = Stream.iterate(0, i -> i++); StreamUtils.zipWithIndex(infStream) .limit(196) .forEach(n -> System.out.println(n.getIndex() + " " + n.getValue()));
通过将generics与匿名接口相结合,您可以基本上创build一个处理枚举的工厂方法。 枚举器callback隐藏下面的迭代器的混乱。
import java.util.Arrays; import java.util.List; import java.util.ListIterator; public class ListUtils2 { public static interface Enumerator<T> { void execute(int index, T value); }; public static final <T> void enumerate(final List<T> list, final Enumerator<T> enumerator) { for (ListIterator<T> it = list.listIterator(); it.hasNext();) { enumerator.execute(it.nextIndex(), it.next()); } } public static final void enumerate(final String[] arr, final Enumerator<String> enumerator) { enumerate(Arrays.asList(arr), enumerator); } public static void main(String[] args) { String[] names = { "John", "Paul", "George", "Ringo" }; enumerate(names, new Enumerator<String>() { @Override public void execute(int index, String value) { System.out.printf("[%d] %s%n", index, value); } }); } }
结果
[0] John [1] Paul [2] George [3] Ringo
扩展的想法
地图,减less,filter
我已经更进了一步,基于这个概念创build了map,reduce和filterfunction。
Google的Guava和Apache公共集合依赖包括类似的function。 你可以检查出来,如你所愿。
import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.ListIterator; public class ListUtils { // ========================================================================= // Enumerate // ========================================================================= public static abstract interface Enumerator<T> { void execute(int index, T value, List<T> list); }; public static final <T> void enumerate(final List<T> list, final Enumerator<T> enumerator) { for (ListIterator<T> it = list.listIterator(); it.hasNext();) { enumerator.execute(it.nextIndex(), it.next(), list); } } // ========================================================================= // Map // ========================================================================= public static interface Transformer<T, U> { U execute(int index, T value, List<T> list); }; public static final <T, U> List<U> transform(final List<T> list, final Transformer<T, U> transformer) { List<U> result = new ArrayList<U>(); for (ListIterator<T> it = list.listIterator(); it.hasNext();) { result.add(transformer.execute(it.nextIndex(), it.next(), list)); } return result; } // ========================================================================= // Reduce // ========================================================================= public static interface Reducer<T, U> { U execute(int index, T value, U result, List<T> list); }; public static final <T, U> U reduce(final List<T> list, final Reducer<T, U> enumerator, U result) { for (ListIterator<T> it = list.listIterator(); it.hasNext();) { result = enumerator.execute(it.nextIndex(), it.next(), result, list); } return result; } // ========================================================================= // Filter // ========================================================================= public static interface Predicate<T> { boolean execute(int index, T value, List<T> list); }; public static final <T> List<T> filter(final List<T> list, final Predicate<T> predicate) { List<T> result = new ArrayList<T>(); for (ListIterator<T> it = list.listIterator(); it.hasNext();) { int index = it.nextIndex(); T value = it.next(); if (predicate.execute(index, value, list)) { result.add(value); } } return result; } // ========================================================================= // Predefined Methods // ========================================================================= // Enumerate public static <T> String printTuples(List<T> list) { StringBuffer buff = new StringBuffer(); enumerate(list, new Enumerator<T>() { @Override public void execute(int index, T value, List<T> list) { buff.append('(').append(index).append(", ") .append(value).append(')'); if (index < list.size() - 1) { buff.append(", "); } } }); return buff.toString(); } // Map public static List<String> intToHex(List<Integer> list) { return transform(list, new Transformer<Integer, String>() { @Override public String execute(int index, Integer value, List<Integer> list) { return String.format("0x%02X", value); } }); } // Reduce public static Integer sum(List<Integer> list) { return reduce(list, new Reducer<Integer, Integer>() { @Override public Integer execute(int index, Integer value, Integer result, List<Integer> list) { return result + value; } }, 0); } // Filter public static List<Integer> evenNumbers(List<Integer> list) { return filter(list, new Predicate<Integer>() { @Override public boolean execute(int index, Integer value, List<Integer> list) { return value % 2 == 0; } }); } // ========================================================================= // Driver // ========================================================================= public static void main(String[] args) { List<Integer> numbers = Arrays.asList(8, 6, 7, 5, 3, 0, 9); // Enumerate System.out.printf("%-10s: %s%n", "Enumerate", printTuples(numbers)); // Map System.out.printf("%-10s: %s%n", "Map", intToHex(numbers)); // Reduce System.out.printf("%-10s: %d%n", "Reduce", sum(numbers)); // Filter System.out.printf("%-10s: %s%n", "Filter", evenNumbers(numbers)); } }
简单而直接
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++; } }
示例用法:
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)); }); }