Java: encontrar elementos duplicados en una secuencia

    Introducción

    Introducida en Java 8, la API Stream se usa comúnmente para filtrar, mapear e iterar sobre elementos. Cuando se trabaja con flujos, una de las tareas habituales es encontrar elementos duplicados.

    En este tutorial, cubriremos varias formas de encontrar elementos duplicados en una secuencia de Java.

    Collectors.toSet ()

    La forma más sencilla de encontrar elementos duplicados es agregando los elementos en un Set. Sets no pueden contener valores duplicados, y el Set.add() el método devuelve un boolean valor que es el resultado de la operación. Si no se agrega un elemento, false se devuelve y viceversa.

    Hagamos un Stream de Strings con algunos valores duplicados. Estos valores se comprueban mediante el equals() , así que asegúrese de tener uno implementado adecuadamente para las clases personalizadas:

    Stream<String> stream = Stream.of("john", "doe", "doe", "tom", "john");
    

    Ahora, hagamos un Set para almacenar los elementos filtrados. Usaremos el filter() método para filtrar valores duplicados y devolverlos:

    Set<String> items = new HashSet<>();
    
    stream.filter(n -> !items.add(n))
            .collect(Collectors.toSet())
            .forEach(System.out::println);
    

    Aquí, intentamos add() cada elemento al Set. Si no se agrega, debido a que está duplicado, recopilamos ese valor y lo imprimimos:

    john
    doe
    

    Collectors.toMap ()

    Alternativamente, también puede contar las ocurrencias de elementos duplicados y mantener esa información en un mapa que contiene los elementos duplicados como claves y su frecuencia como valores.

    Vamos a crear un List de Integer tipo:

    List<Integer> list = Arrays.asList(9, 2, 2, 7, 6, 6, 5, 7);
    

    Luego, recopilemos los elementos en un Map y contar sus ocurrencias:

    Map<Integer, Integer> map = list.stream()
            .collect(Collectors.toMap(Function.identity(), value -> 1, Integer::sum));
            
    System.out.println(map);
    

    No hemos eliminado ningún elemento, solo contamos sus apariciones y las almacenamos en un Map:

    {2=2, 5=1, 6=2, 7=2, 9=1}
    

    Collectors.groupingBy (Function.identity (), Collectors.counting ()) con Collectors.toList ()

    los Collectors.groupingBy() El método se utiliza para agrupar elementos, según alguna propiedad, y devolverlos como un Map ejemplo.

    En nuestro caso, el método recibe dos parámetros: Function.identity(), que siempre devuelve sus argumentos de entrada y Collectors.counting(), que cuenta los elementos pasados ​​en la secuencia.

    Entonces, usaremos el groupingBy() método para crear un mapa de la frecuencia de estos elementos. Después de eso, podemos simplemente filter() el flujo de elementos que tienen una frecuencia superior a 1:

    list.stream()
            // Creates a map {4:1, 5:2, 7:2, 8:2, 9:1}
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
            .entrySet()
            // Convert back to stream to filter
            .stream()
            .filter(element -> element.getValue() > 1)
            // Collect elements to List and print out the values
            .collect(Collectors.toList())
            .forEach(System.out::println);
    

    Esto resulta en:

    5=2
    7=2
    8=2
    

    Si desea extraer solo los elementos duplicados, sin su frecuencia, puede agregar una map() en el proceso. Después de filtrar y antes de recopilar una lista, obtendremos solo las claves:

    .map(Map.Entry::getKey)
    

    Colecciones.frecuencia ()

    Collections.frequency() es otro método que proviene de la clase Colecciones de Java que cuenta las apariciones de un elemento especificado en el flujo de entrada atravesando cada elemento. Se necesitan dos parámetros, la colección y el elemento cuya frecuencia se va a determinar.

    Ahora bien filter() la secuencia para cada elemento que tiene un frequency() mayor que 1:

    list.stream()
            .filter(i -> Collections.frequency(list, i) > 1)
            //Collect elements to a Set and print out the values 
            .collect(Collectors.toSet())
            .forEach(System.out::println);
    

    Aquí, podemos recolectar a un Set oa un List. Si recopilamos en una lista, tendrá todos los elementos duplicados, por lo que algunos pueden repetirse. Si recopilamos en un conjunto, tendrá elementos duplicados únicos.

    Esto resulta en:

    5
    7
    8
    

    Stream.distinct ()

    los distinct() El método es un método con estado (mantiene el estado de los elementos anteriores en mente) y compara elementos usando equals() método. Si son distintos / únicos, se devuelven, que podemos completar en otra lista.

    Hagamos una lista con algunos valores duplicados y extraigamos los valores distintos:

    List<String> list = new ArrayList(Arrays.asList("A", "B", "C", "D", "A", "B", "C", "A", "F", "C"));
    
    List<String> distinctElementList = list.stream()
            .distinct()
            .collect(Collectors.toList());
    

    Ahora, todos los valores no distintos tienen más de una ocurrencia. Si eliminamos los valores distintos, nos quedarán elementos duplicados:

    for (String distinctElement : distinctElementList) {
        list.remove(distinctElement);
    }
    

    Ahora, imprimamos los resultados:

    list.forEach(System.out::print)
    

    Estos son los elementos duplicados, con sus respectivas ocurrencias:

    ABCAC
    

    Si también desea examinarlos, y solo mostrar una aparición de cada elemento duplicado (en lugar de todos ellos por separado), puede ejecutarlos a través del distinct() método de nuevo:

    list.stream()
            .distinct()
            .collect(Collectors.toList())
            .forEach(System.out::print);
    

    Esto resulta en:

    ABC
    

    Conclusión

    En este artículo, hemos repasado algunos enfoques para encontrar elementos duplicados en una secuencia de Java.

    Hemos cubierto el Stream.distinct() método de la API Stream, el Collectors.toSet(), Collectors.toMap() y Collectors.groupingBy() métodos de Java Collectors, así como Collections.frequency() método del marco de las colecciones.

     

    Etiquetas:

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *