Is there a Java equivalent of Python's 'enumerate' function?

前端 未结 11 567
别那么骄傲
别那么骄傲 2020-12-08 01:59

In Python, the enumerate function allows you to iterate over a sequence of (index, value) pairs. For example:

>>> numbers = [\"zero\", \"one\", \"tw         


        
相关标签:
11条回答
  • 2020-12-08 02:17

    According to the Python docs (here), this is the closest you can get with Java, and it's no more verbose:

    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]);
    }
    

    If you need to use the List class...

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

    *NOTE: if you need to modify the list as you're traversing it, you'll need to use the Iterator object, as it has the ability to modify the list without raising a ConcurrentModificationException.

    0 讨论(0)
  • 2020-12-08 02:18

    I find this to be the most similar to the python approach.

    Usage

    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);
        }
    }
    

    Output

    0 zero
    1 one
    2 two
    
    3 zero
    4 one
    5 two
    

    Features

    • Works on any iterable
    • Does not create an in-memory list copy (suitable for large lists)
    • Supports native for each syntax
    • Accepts a start parameter which can be added to the index

    Implementation

    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);
        }
    
    }
    
    0 讨论(0)
  • 2020-12-08 02:21
    List<String> list = { "foo", "bar", "foobar"};
    int i = 0;
    for (String str : list){
         System.out.println(i++ + str );
    }
    
    0 讨论(0)
  • 2020-12-08 02:23

    Pretty much the same syntax using Java8 Streams

        ArrayList<String> numbers = new ArrayList<String>();
        numbers.add("one");
        numbers.add("two");
        numbers.add("three");
    
        numbers.stream().forEach(num ->
        {
            System.out.println(numbers.indexOf(num) + " " + num);
        });
    
    0 讨论(0)
  • 2020-12-08 02:27

    Now with Java 8s Stream API together with the small ProtonPack library providing StreamUtils it can be achieved easily.

    The first example uses the same for-each notation as in the question:

    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());
    }
    

    Above although does not provide the lazy evaluation as in Python. For that you must use the forEach() Stream API method:

    Stream<String> numbers = Arrays.stream("zero one two".split(" "));
    StreamUtils.zipWithIndex(numbers)
            .forEach(n -> System.out.println(n.getIndex() + " " + n.getValue()));
    

    The lazy evaluation can be verified with the following infinite stream:

    Stream<Integer> infStream = Stream.iterate(0, i -> i++);
    StreamUtils.zipWithIndex(infStream)
            .limit(196)
            .forEach(n -> System.out.println(n.getIndex() + " " + n.getValue()));
    
    0 讨论(0)
提交回复
热议问题