¿Cómo puedo simplificar este código en una sola expresión lambda? La idea es que hay una lista de mapas y me gustaría crear una nueva lista de mapas, usando un filtro en la clave. En este ejemplo, quiero reasignarlo para que solo conserve las teclas "x" y "z".
Map<String, String> m0 = new LinkedHashMap<>(); m0.put("x", "123"); m0.put("y", "456"); m0.put("z", "789"); Map<String, String> m1 = new LinkedHashMap<>(); m1.put("x", "000"); m1.put("y", "111"); m1.put("z", "222"); List<Map> l = new ArrayList<>(Arrays.asList(m0, m1)); List<Map> tx = new ArrayList<>(); for(Map<String, String> m : l) { Map<String, String> filtered = m.entrySet() .stream() .filter(map -> map.getKey().equals("x") || map.getKey().equals("z")) .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue())); tx.add(filtered); } System.err.println("l: " + l); System.err.println("tx: " + tx);Producción:
l: [{x=123, y=456, z=789}, {x=000, y=111, z=222}] tx: [{x=123, z=789}, {x=000, z=222}]Por supuesto, puede convertir toda su operación en una sola operación Stream.
// no need to copy a List (result of Array.asList) to an ArrayList, by the way List<Map<String, String>> l = Arrays.asList(m0, m1); List<Map<String, String>> tx = l.stream().map(m -> m.entrySet().stream() .filter(map -> map.getKey().equals("x") || map.getKey().equals("z")) .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()))) .collect(Collectors.toList()); Pero tenga en cuenta que la transmisión sobre un Map y el filtrado es una operación con una complejidad de tiempo lineal, ya que comparará cada clave de cada mapa con el filtro, mientras que solo tiene una cantidad muy pequeña de claves reales que desea conservar. Entonces aquí, es mucho más simple y más eficiente (para mapas más grandes) usar
List<Map<String, String>> tx = l.stream() .map(m -> Stream.of("x", "y") .filter(m::containsKey).collect(Collectors.toMap(key->key, m::get))) .collect(Collectors.toList()); que solo realizará cuatro búsquedas por mapa. Si le molesta, incluso podría reducirlo a dos búsquedas, sin embargo, el factor constante es irrelevante para la complejidad del tiempo general, que será el tiempo constante, si el mapa tiene una búsqueda de tiempo constante, como HashMap . Incluso para mapas con complejidad de tiempo de búsqueda O(log(n)) , como TreeMap , esto será más eficiente que el escaneo lineal, si los mapas son más grandes que las tres asignaciones del código de ejemplo.
Puedes intentar algo como esto:
List<Map<String, String>> l = Arrays.asList(m0, m1); l.forEach(map -> { map.entrySet().removeIf(e -> !e.getKey().equals("x") && !e.getKey().equals("z")); }); Simplemente elimina todas las asignaciones en cada Map<String, String> si la clave de entrada no es x o z .
Editar: ¡Debe utilizar el método equivalente de Radiodef, pero más corto!
List<Map<String, String>> l = Arrays.asList(m0, m1); l.forEach(map -> map.keySet().retainAll(Arrays.asList("x", "z"));Pruebe el siguiente código (declaré una lista para desiredKeys ):
public class Main { public static void main(String[] args) { Map<String, String> m0 = new HashMap<>(); m0.put("x", "123"); m0.put("y", "456"); m0.put("z", "789"); Map<String, String> m1 = new HashMap<>(); m1.put("x", "000"); m1.put("y", "111"); m1.put("z", "222"); List<Map<String, String>> l = new ArrayList<>(Arrays.asList(m0, m1)); List<String> desiredKeys = Lists.newArrayList("x", "z"); List<Map<String, String>> transformed = l.stream().map(map -> map.entrySet().stream() .filter(e -> desiredKeys.stream().anyMatch(k -> k.equals(e.getKey()))) .collect(Collectors.toMap(e -> e.getKey(), p -> p.getValue()))).filter(m -> !m.isEmpty()).collect(Collectors.toList()); System.err.println(l); System.err.println(transformed); } }