it-swarm.com.de

Gibt es ein Java-Äquivalent zu Pythons Enumerate-Funktion?

In Python können Sie mit der enumerate - Funktion eine Folge von (Index-, Wert-) Paaren durchlaufen. Zum Beispiel:

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

Gibt es eine Möglichkeit, dies in Java zu tun? 

59
Richard Fearn

Bei Sammlungen, die die Schnittstelle " List " implementieren, können Sie die Methode listIterator() aufrufen, um eine ListIterator abzurufen. Der Iterator hat (unter anderem) zwei Methoden - nextIndex() , um den Index zu erhalten; und next() , um den Wert zu erhalten (wie bei anderen Iteratoren).

Ein Java-Äquivalent des obigen Python könnte also sein:

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

was wie der Python ausgibt:

0 zero
1 one
2 two
50
Richard Fearn

Ich finde, dass dies dem Python-Ansatz am ähnlichsten ist.

Verwendungszweck

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

Ausgabe

0 zero
1 one
2 two

3 zero
4 one
5 two

Eigenschaften

  • Funktioniert auf jedem iterable
  • Erstellt keine Kopie einer In-Memory-Liste (geeignet für große Listen)
  • Unterstützt native für jede Syntax
  • Akzeptiert einen Startparameter, der dem Index hinzugefügt werden kann

Implementierung

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

}
11
Pace

Streng genommen nein, da die Funktion enumerate () in Python eine Liste von Tupeln zurückgibt und Tupel in Java nicht vorhanden sind.

Wenn Sie sich jedoch nur für printing eines Indexes und eines Werts interessieren, können Sie den Vorschlag von Richard Fearn folgen und nextIndex () und next () auf einem Iterator verwenden.

Beachten Sie auch, dass enumerate () mithilfe der allgemeineren Funktion Zip () (mithilfe der Python-Syntax) definiert werden kann:

mylist = list("abcd")
Zip(range(len(mylist)), mylist)

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

Wenn Sie Ihre eigene Tuple-Klasse definieren (siehe Verwenden von Paaren oder 2-Tupeln in Java als Ausgangspunkt), können Sie sicherlich Ihre eigene Zip () - Funktion in Java schreiben, um sie zu verwenden (mithilfe von Tuple) Klasse definiert im Link):

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

Und sobald Sie Zip () haben, ist die Implementierung von enumerate () trivial.

Edit: langsamer Tag bei der Arbeit, um es abzuschließen:

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

Edit 2: Wie in den Kommentaren zu dieser Frage hervorgehoben, ist dies nicht völlig gleichwertig. Es erzeugt zwar dieselben Werte wie die Aufzählung von Python, jedoch nicht auf die generative Art und Weise, die auch die Aufzählung von Python gilt. Daher kann dieser Ansatz für große Sammlungen durchaus untragbar sein.

8
Adam Parkin

Laut den Python-Dokumenten ( hier ) ist dies das nächstgelegene, das Sie mit Java bekommen können, und es ist nicht mehr wortreich:

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

Wenn Sie die List-Klasse verwenden müssen ...

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

* HINWEIS: Wenn Sie die Liste während des Durchlaufens ändern müssen, müssen Sie das Iterator-Objekt verwenden, da es die Möglichkeit hat, die Liste zu ändern, ohne eine ConcurrentModificationException zu erzeugen.

4
Travis
List<String> list = { "foo", "bar", "foobar"};
int i = 0;
for (String str : list){
     System.out.println(i++ + str );
}
2
Heisenbug

Durch die Kombination von Generics mit anonymen Schnittstellen können Sie im Wesentlichen eine Factory-Methode für die Auflistung von Handlungen erstellen. Der Enumerator-Callback verbirgt die Unordnung des Iterators darunter.

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

Ergebnis

[0] John
[1] Paul
[2] George
[3] Ringo

Erweiterte Gedanken

Karte, Reduzieren, Filtern

Ich habe dies noch einen Schritt weiter gemacht und basierend auf diesem Konzept Karten-, Reduzierungs- und Filterfunktionen erstellt.

Die Abhängigkeiten von Google Guava und Apache common-collection enthalten eine ähnliche Funktionalität. Sie können sie nach Belieben prüfen.

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));
    }
}
1
Mr. Polywhirl

Nein. Vielleicht gibt es einige Bibliotheken, die eine solche Funktionalität unterstützen. Wenn Sie jedoch auf die Standardbibliotheken zurückgreifen, ist es Ihre Aufgabe zu zählen.

1
rocksportrocker

Ich denke, das sollte die Java-Funktionalität sein, die dem Python am meisten "Aufzählen" ähnelt, obwohl es ziemlich kompliziert und ineffektiv ist. Ordnen Sie einfach die Indizes der Liste mithilfe von ListIterator oder Collector ihren Elementen zu:

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

oder mit Lambda-Ausdruck:

Set<Integer, String> enumeration = IntStream.range(0, list.size()).boxed.collect(Collectors.toMap(index -> index, index -> list.get(index)));

dann können Sie es mit einer erweiterten for-Schleife verwenden:

for (Map.Entry<Integer, String> entry : enumeration.entrySet){
    System.out.println(entry.getKey() + "\t" + entry.getValue());
}
1
charlieh_7

Einfach und unkompliziert

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

Verwendungsbeispiel:

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

Mit der Java 8s Stream API zusammen mit der kleinen ProtonPack library, die StreamUtils bereitstellt, kann dies problemlos erreicht werden.

Das erste Beispiel verwendet für jede Notation die gleiche wie in der Frage:

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

Oben, obwohl die faule Auswertung nicht wie in Python bereitgestellt wird ..__ Dazu müssen Sie die forEach() Stream API-Methode verwenden:

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

Die faule Bewertung kann mit dem folgenden unendlichen Strom überprüft werden:

Stream<Integer> infStream = Stream.iterate(0, i -> i++);
StreamUtils.zipWithIndex(infStream)
        .limit(196)
        .forEach(n -> System.out.println(n.getIndex() + " " + n.getValue()));
0
sevenforce