Comprensión de listas tipo Python en Java


Dado que Java no permite pasar métodos como parámetros, ¿qué truco usa para implementar Python como la comprensión de listas en Java ?

Tengo una lista (ArrayList) de Cadenas. 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 que se puede dar la lista y la función como parámetros para que pueda obtener una lista de nuevo con cada elemento procesado. No es posible en el sentido literal, pero ¿qué truco debo usar ?

La otra opción es escribir una nueva función para cada función de procesamiento de cadenas más pequeña que simplemente recorre toda la lista, lo que no es tan genial.

Author: S.Lott, 2009-05-22

6 answers

Básicamente, se crea una interfaz de función:

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

Y luego pasa una subclase anónima a tu método.

Su método podría aplicar la función a cada elemento en su lugar:

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 crear un nuevo List (básicamente creando una asignación de 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 en el lugar puede ser la única viable; si desea aplicar muchos diferentes funciones a la misma lista original para hacer muchas listas derivadas, querrá la versión map.

 33
Author: Michael Myers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-22 18:57:57

En Java 8 puedes usar referencias de métodos:

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

O, si desea crear una nueva instancia de lista:

List<String> upper = list.stream().map(String::toUpperCase).collect(Collectors.toList());
 36
Author: yurez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-21 10:06:39

La biblioteca Google Collections tiene muchas clases para trabajar con colecciones e iteradores a un nivel mucho más alto que el que soporta Java, y de una manera funcional (filter, map, fold, etc.).). Define interfaces de funciones y Predicados y métodos que los utilizan para procesar colecciones para que usted no tenga que hacerlo. También tiene funciones de conveniencia que hacen que tratar con genéricos Java sea menos arduo.

También uso Hamcrest * * para filtrar colecciones.

Las dos bibliotecas son fáciles de combinar con clases de adaptador.


* * Declaración de interés: Co-escribí Hamcrest

 16
Author: Nat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-22 18:31:52
 5
Author: Michael Myers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-22 20:26:30

Estoy construyendo este proyecto para escribir comprensión de lista 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}
 1
Author: farolfo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-18 18:58:19

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"]
 0
Author: MrYurihi redstone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-23 12:35:53