web-dev-qa-db-fra.com

Ignorer les doublons lors de la création d'une carte à l'aide de flux

Map<String, String> phoneBook=people.stream()
                                    .collect(toMap(Person::getName, Person::getAddress));

Je reçois une exception de clé en double lorsque des doublons se produisent. 

Est-il possible d'ignorer d'ajouter les valeurs à mapper lorsque les doublons se produisent?

Quand il y a des doublons, il devrait simplement continuer en ignorant cette clé en double.

168
Patan

Ceci est possible en utilisant le paramètre mergeFunction de Collectors.toMap(keyMapper, valueMapper, mergeFunction) :

Map<String, String> phoneBook = 
    people.stream()
          .collect(Collectors.toMap(
             Person::getName,
             Person::getAddress,
             (address1, address2) -> {
                 System.out.println("duplicate key found!");
                 return address1;
             }
          ));

mergeFunction est une fonction qui opère sur deux valeurs associées à la même clé. adress1 correspond à la première adresse rencontrée lors de la collecte d'éléments et adress2 correspond à la deuxième adresse rencontrée: ce lambda indique simplement de conserver la première adresse et ignore la deuxième.

311
Tunaki

Comme indiqué dans JavaDocs :

Si les clés mappées contiennent des doublons (selon Object.equals(Object)), une IllegalStateException est renvoyée lorsque le fichier l'opération de collecte est effectuée. Si les clés mappées peuvent avoir les doublons, utilisez toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction) à la place.

Vous devriez donc utiliser toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction) à la place. Il suffit de fournir la fonction de fusion, qui déterminera lequel des doublons doit être mis en carte. Par exemple, si vous ne vous souciez pas de laquelle, appelez simplement

Map<String, String> phoneBook = people.stream()
  .collect(Collectors.toMap(Person::getName, Person::getAddress, (p1, p2) -> p1));
65
alaster

J'ai rencontré un tel problème lors du regroupement d'objet, je les ai toujours résolus de manière simple: effectuez un filtre personnalisé à l'aide d'un fichier Java.util.Set pour supprimer les objets en double avec l'attribut de votre choix (voir ci-dessous).

Set<String> uniqueNames = new HashSet<>();
Map<String, String> phoneBook = people
                  .stream()
                  .filter(person -> person != null && !uniqueNames.add(person.getName()))
                  .collect(toMap(Person::getName, Person::getAddress));

J'espère que cela aide tous ceux qui ont le même problème!

0
Shessuky

La réponse @alaster m'aide beaucoup, mais j'aimerais ajouter une information utile si quelqu'un essaie de la regrouper.

Si vous avez, par exemple, deux Orders avec le même code mais différent quantity de produits pour chaque produit et si vous désirez somme les quantités, vous pouvez faire

List<Order> listQuantidade = new ArrayList<>();
listOrders.add(new Order("COD_1", 1L));
listOrders.add(new Order("COD_1", 5L));
listOrders.add(new Order("COD_1", 3L));
listOrders.add(new Order("COD_2", 3L));
listOrders.add(new Order("COD_3", 4L));

listOrders.collect(Collectors.toMap(Order::getCode, o -> o.getQuantity(), (o1, o2) -> o1 + o2));

Résultat:

{COD_3=4, COD_2=3, COD_1=9}
0
Dherik

En supposant que vous avez des gens est la liste d'objet 

  Map<String, String> phoneBook=people.stream()
                                        .collect(toMap(Person::getName, Person::getAddress));

Maintenant, vous avez besoin de deux étapes:

1) 

people =removeDuplicate(people);

2) 

Map<String, String> phoneBook=people.stream()
                                        .collect(toMap(Person::getName, Person::getAddress));

Voici la méthode pour supprimer les doublons 

public static List removeDuplicate(Collection<Person>  list) {
        if(list ==null || list.isEmpty()){
            return null;
        }

        Object removedDuplicateList =
                list.stream()
                     .distinct()
                     .collect(Collectors.toList());
     return (List) removedDuplicateList;

      }

Ajout de l'exemple complet ici

 package com.example.khan.vaquar;

import Java.util.Arrays;
import Java.util.Collection;
import Java.util.List;
import Java.util.Map;
import Java.util.stream.Collectors;

public class RemovedDuplicate {

    public static void main(String[] args) {
        Person vaquar = new Person(1, "Vaquar", "Khan");
        Person zidan = new Person(2, "Zidan", "Khan");
        Person zerina = new Person(3, "Zerina", "Khan");

        // Add some random persons
        Collection<Person> duplicateList = Arrays.asList(vaquar, zidan, zerina, vaquar, zidan, vaquar);

        //
        System.out.println("Before removed duplicate list" + duplicateList);
        //
        Collection<Person> nonDuplicateList = removeDuplicate(duplicateList);
        //
        System.out.println("");
        System.out.println("After removed duplicate list" + nonDuplicateList);
        ;

        // 1) solution Working code
        Map<Object, Object> k = nonDuplicateList.stream().distinct()
                .collect(Collectors.toMap(s1 -> s1.getId(), s1 -> s1));
        System.out.println("");
        System.out.println("Result 1 using method_______________________________________________");
        System.out.println("k" + k);
        System.out.println("_____________________________________________________________________");

        // 2) solution using inline distinct()
        Map<Object, Object> k1 = duplicateList.stream().distinct()
                .collect(Collectors.toMap(s1 -> s1.getId(), s1 -> s1));
        System.out.println("");
        System.out.println("Result 2 using inline_______________________________________________");
        System.out.println("k1" + k1);
        System.out.println("_____________________________________________________________________");

        //breacking code
        System.out.println("");
        System.out.println("Throwing exception _______________________________________________");
        Map<Object, Object> k2 = duplicateList.stream()
                .collect(Collectors.toMap(s1 -> s1.getId(), s1 -> s1));
        System.out.println("");
        System.out.println("k2" + k2);
        System.out.println("_____________________________________________________________________");
    }

    public static List removeDuplicate(Collection<Person> list) {
        if (list == null || list.isEmpty()) {
            return null;
        }

        Object removedDuplicateList = list.stream().distinct().collect(Collectors.toList());
        return (List) removedDuplicateList;

    }

}

// Model class
class Person {
    public Person(Integer id, String fname, String lname) {
        super();
        this.id = id;
        this.fname = fname;
        this.lname = lname;
    }

    private Integer id;
    private String fname;
    private String lname;

    // Getters and Setters

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getFname() {
        return fname;
    }

    public void setFname(String fname) {
        this.fname = fname;
    }

    public String getLname() {
        return lname;
    }

    public void setLname(String lname) {
        this.lname = lname;
    }

    @Override
    public String toString() {
        return "Person [id=" + id + ", fname=" + fname + ", lname=" + lname + "]";
    }

}

Résultats :

Before removed duplicate list[Person [id=1, fname=Vaquar, lname=Khan], Person [id=2, fname=Zidan, lname=Khan], Person [id=3, fname=Zerina, lname=Khan], Person [id=1, fname=Vaquar, lname=Khan], Person [id=2, fname=Zidan, lname=Khan], Person [id=1, fname=Vaquar, lname=Khan]]

After removed duplicate list[Person [id=1, fname=Vaquar, lname=Khan], Person [id=2, fname=Zidan, lname=Khan], Person [id=3, fname=Zerina, lname=Khan]]

Result 1 using method_______________________________________________
k{1=Person [id=1, fname=Vaquar, lname=Khan], 2=Person [id=2, fname=Zidan, lname=Khan], 3=Person [id=3, fname=Zerina, lname=Khan]}
_____________________________________________________________________

Result 2 using inline_______________________________________________
k1{1=Person [id=1, fname=Vaquar, lname=Khan], 2=Person [id=2, fname=Zidan, lname=Khan], 3=Person [id=3, fname=Zerina, lname=Khan]}
_____________________________________________________________________

Throwing exception _______________________________________________
Exception in thread "main" Java.lang.IllegalStateException: Duplicate key Person [id=1, fname=Vaquar, lname=Khan]
    at Java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.Java:133)
    at Java.util.HashMap.merge(HashMap.Java:1253)
    at Java.util.stream.Collectors.lambda$toMap$58(Collectors.Java:1320)
    at Java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.Java:169)
    at Java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.Java:948)
    at Java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.Java:481)
    at Java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.Java:471)
    at Java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.Java:708)
    at Java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.Java:234)
    at Java.util.stream.ReferencePipeline.collect(ReferencePipeline.Java:499)
    at com.example.khan.vaquar.RemovedDuplicate.main(RemovedDuplicate.Java:48)
0
vaquar khan