Pregunta

Dado que Java no permite pasar métodos como parámetros, qué truco que utiliza para aplicar Python como lista por comprensión en Java?

Tengo una lista (ArrayList) de cadenas. Necesito transformar cada elemento mediante el uso de una función para que llegue otra lista. Tengo varias funciones que tienen una cadena como entrada y volver 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 vuelta con cada elemento de procesado. No es posible, en el sentido literal, sino qué truco se debe usar?

La otra opción es escribir una nueva función para cada función de menor procesamiento de cadenas, que simplemente bucles sobre toda la lista, que no es algo tan cool.

¿Fue útil?

Solución

Básicamente, se crea una interfaz Función:

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

y luego pasar en una subclase anónimo a su método.

Su método podría o bien aplicar la función de cada elemento en el 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 una nueva List (básicamente la creación de un mapeo 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 la lista es muy grande, la solución en el lugar puede ser la única viable uno; Si se desea aplicar muchas funciones diferentes a la misma lista original para hacer muchas listas de derivados, tendrá la versión map.

Otros consejos

En Java 8 se puede utilizar referencias de métodos:

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

O, si desea crear una nueva instancia de la lista:

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

El biblioteca de Google Colecciones tiene un montón de clases para trabajar con las colecciones y los iteradores en un nivel mucho más alto que sencilla Java soporta, y de una manera funcional (filtro, mapa, plegado, etc.). En él se definen las interfaces y métodos que los utilizan para procesar colecciones de modo que usted no tiene que la función y el predicado. También cuenta con funciones de confort que hacen que se ocupan de los genéricos de Java menos arduo.

Hamcrest ** para las colecciones de filtrado.

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


** Declaración de interés: I co-escribió Hamcrest

Estoy construyendo este proyecto de escribir la lista de la 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}

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

devolverá:

["1", "2", "3", "4", "cheese"]
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top