java - recorrer - listas de comprension en python
Comprensión de lista de Python en Java (6)
Como Java no permite pasar los métodos como parámetros, ¿qué truco utilizas para implementar Python como la comprensión de listas en Java?
Tengo una lista (ArrayList) de Strings. Necesito transformar cada elemento usando una función para obtener otra lista. Tengo varias funciones que toman una cadena como entrada y devuelven otra cadena como salida. ¿Cómo hago un método genérico al que se le puede dar la lista y la función como parámetros para que pueda obtener una lista con cada elemento procesado? No es posible en el sentido literal, pero ¿qué truco debería usar?
La otra opción es escribir una nueva función para cada función más pequeña de procesamiento de cadenas que simplemente recorre toda la lista, lo que no es tan genial.
Apache Commons CollectionsUtil.transform (Colección, Transformador) es otra opción.
Básicamente, creas una interfaz de Función:
public interface Func<In, Out> {
public Out apply(In in);
}
y luego pasar una subclase anónima a su método.
Su método podría aplicar la función a cada elemento in situ:
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();
}
});
o cree una nueva List
(básicamente, crear una asignación desde la lista de entrada a la lista de salida):
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();
}
});
Cuál es preferible depende de su caso de uso. Si su lista es extremadamente grande, la solución in situ puede ser la única viable; si desea aplicar muchas funciones diferentes a la misma lista original para hacer muchas listas derivadas, querrá la versión del map
.
En Java 8 puedes usar referencias de métodos:
List<String> list = ...;
list.replaceAll(String::toUpperCase);
O bien, si desea crear una nueva instancia de lista:
List<String> upper = list.stream().map(String::toUpperCase).collect(Collectors.toList());
Estoy construyendo este proyecto para escribir listas de comprensión en Java, ahora es una prueba de concepto en https://github.com/farolfo/list-comprehension-in-java
Ejemplos
// { 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};
Y si queremos transformar la expresión de salida de alguna manera como
// { 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}
La biblioteca de colecciones de Google tiene muchas clases para trabajar con colecciones e iteradores a un nivel mucho más alto que los soportes de Java simple, y de una manera funcional (filtro, mapa, plegado, etc.). Define las interfaces y los métodos de función y predicado que los utilizan para procesar las colecciones de manera que no sea necesario. También tiene funciones de conveniencia que hacen que lidiar con los genéricos Java sea menos arduo.
También uso Hamcrest ** para filtrar colecciones.
Las dos bibliotecas son fáciles de combinar con clases de adaptadores.
** Declaración de interés: co-escribí Hamcrest
Puedes usar lambdas para la función, así:
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;
}
}
el uso:
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
)))
});
volverá:
["1", "2", "3", "4", "cheese"]