Python-ähnliches Listenverständnis in Java

Da Java nicht erlaubt, Methoden als Parameter zu übergeben, welchen Trick verwenden Sie, um Python wie Listenverständnis in Java zu implementieren?

Ich habe eine Liste (ArrayList) von Strings. Ich muss jedes Element mit einer Funktion umwandeln, damit ich eine andere Liste bekomme. Ich habe mehrere Funktionen, die einen String als Eingabe nehmen und einen anderen String als Ausgabe zurückgeben. Wie mache ich eine generische Methode, die die Liste und die Funktion als Parameter gegeben werden kann, damit ich eine Liste mit jedem verarbeiteten Element erhalten kann. Es ist nicht möglich im wörtlichen Sinne, aber was für ein Trick sollte ich verwenden?

Die andere Möglichkeit besteht darin, für jede kleinere String-Processing-Funktion eine neue Funktion zu schreiben, die einfach über die gesamte Liste schlägt, was ja nicht so cool ist.

6 Solutions collect form web for “Python-ähnliches Listenverständnis in Java”

Grundsätzlich erstellen Sie eine Funktionsschnittstelle:

public interface Func<In, Out> { public Out apply(In in); } 

Und dann eine anonyme Unterklasse an deine Methode weitergeben.

Ihre Methode könnte entweder die Funktion an jedem Element an Ort und Stelle anwenden:

 public static <T> void applyToListInPlace(List<T> list, Func<T, T> f) { ListIterator<T> itr = list.listIterator(); while (itr.hasNext()) { T output = f.apply(itr.next()); itr.set(output); } } // ... List<String> myList = ...; applyToListInPlace(myList, new Func<String, String>() { public String apply(String in) { return in.toLowerCase(); } }); 

Oder eine neue List erstellen (grundsätzlich eine Zuordnung aus der Eingabeliste zur Ausgabeliste erstellen):

 public static <In, Out> List<Out> map(List<In> in, Func<In, Out> f) { List<Out> out = new ArrayList<Out>(in.size()); for (In inObj : in) { out.add(f.apply(inObj)); } return out; } // ... List<String> myList = ...; List<String> lowerCased = map(myList, new Func<String, String>() { public String apply(String in) { return in.toLowerCase(); } }); 

Welches ist vorzuziehen hängt von Ihrem Anwendungsfall ab. Wenn Ihre Liste extrem groß ist, kann die in-Place-Lösung die einzig lebensfähige sein; Wenn Sie viele verschiedene Funktionen auf die gleiche Originalliste anwenden möchten, um viele Ableitungslisten zu erstellen, werden Sie die map wünschen.

In Java 8 können Sie Methodenreferenzen verwenden:

 List<String> list = ...; list.replaceAll(String::toUpperCase); 

Oder wenn Sie eine neue Listeninstanz erstellen möchten:

 List<String> upper = list.stream().map(String::toUpperCase).collect(Collectors.toList()); 

Die Google Collections-Bibliothek verfügt über viele Klassen für die Arbeit mit Sammlungen und Iteratoren auf einer viel höheren Ebene als einfache Java-Unterstützung und in einer funktionalen Weise (Filter, Karte, Falte, etc.). Es definiert Funktion und Predicate Schnittstellen und Methoden, die sie verwenden, um Sammlungen zu verarbeiten, so dass Sie nicht müssen. Es hat auch Bequemlichkeitsfunktionen, die den Umgang mit Java-Generika weniger anstrengend machen.

Ich benutze auch Hamcrest ** zum Filtern von Sammlungen.

Die beiden Bibliotheken lassen sich leicht mit Adapterklassen kombinieren.


** Interessenserklärung: Ich habe Hamcrest geschrieben

Apache Commons CollectionsUtil.transform (Collection, Transformer) ist eine weitere Option.

Ich baue dieses Projekt, um Listenverständnis in Java zu schreiben, jetzt ist ein Beweis des Konzepts in https://github.com/farolfo/list-comprehension-in-java

Beispiele

 // { x | x E {1,2,3,4} ^ x is even } // gives {2,4} Predicate<Integer> even = x -> x % 2 == 0; List<Integer> evens = new ListComprehension<Integer>() .suchThat(x -> { x.belongsTo(Arrays.asList(1, 2, 3, 4)); x.is(even); }); // evens = {2,4}; 

Und wenn wir den Ausgabeausdruck in irgendeiner Weise umwandeln wollen

 // { x * 2 | x E {1,2,3,4} ^ x is even } // gives {4,8} List<Integer> duplicated = new ListComprehension<Integer>() .giveMeAll((Integer x) -> x * 2) .suchThat(x -> { x.belongsTo(Arrays.asList(1, 2, 3, 4)); x.is(even); }); // duplicated = {4,8} 

Du kannst Lambdas für die Funktion verwenden, so wie:

 class Comprehension<T> { /** *in: List int *func: Function to do to each entry */ public List<T> comp(List<T> in, Function<T, T> func) { List<T> out = new ArrayList<T>(); for(T o: in) { out.add(func.apply(o)); } return out; } } 

die Verwendung:

 List<String> stuff = new ArrayList<String>(); stuff.add("a"); stuff.add("b"); stuff.add("c"); stuff.add("d"); stuff.add("cheese"); List<String> newStuff = new Comprehension<String>().comp(stuff, (a) -> { //The <String> tells the comprehension to return an ArrayList<String> a.equals("a")? "1": (a.equals("b")? "2": (a.equals("c")? "3": (a.equals("d")? "4": a ))) }); 

wird zurückkehren:

 ["1", "2", "3", "4", "cheese"] 
  • Multiprozess mit seriellem Objekt als Parameter
  • Übergeben Sie den Spaltennamen als Parameter an PostgreSQL mit psycopg2
  • Tornado nächster Abfrage-String URL-Parameter
  • Programmgesteuertes Bestimmen der Anzahl von Parametern erfordert eine Funktion - Python
  • Aufruf von Funktionen mit Parametern mit einem Wörterbuch in Python
  • Python ist die beste Programmiersprache der Welt.