Ігноруйте дублікати при створенні карти за допомогою потоків


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

я отримав java.lang.IllegalStateException: Duplicate key коли знайдений дублюваний елемент.

Чи можна ігнорувати такий виняток при додаванні значень на карту?

Коли є дублікат, його просто слід продовжувати, ігноруючи цей дублікат ключа.


Якщо ви можете використовувати його, HashSet проігнорує ключ, якщо він вже є.
sahitya

@ капітан-арябхатта. Чи можна мати ключові значення в хештеті
Патан,

Відповіді:


448

Це можливо за допомогою mergeFunctionпараметра 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це функція, яка працює на двох значеннях, пов'язаних з одним і тим же ключем. adress1відповідає першій адресі, яка зустрічалася під час збирання елементів, і adress2відповідає другій зустріченій адресі: ця лямбда просто говорить про збереження першої адреси, а другу ігнорує.


5
Я розгублений, чому не дозволяється повторювати значення (не ключі)? І як дозволити повторювані значення?
Хенді Іраван

чи є можливість отримати ключ, за який відбувається зіткнення? відповідь тут: stackoverflow.com/questions/40761954/…
Гійом

2
Чи можна повністю проігнорувати цей запис, якщо відбувається зіткнення? В основному, якщо я коли-небудь стикаюся з повторюваними ключами, я не хочу, щоб вони взагалі були додані. У наведеному вище прикладі я не хочу адреси1 або адреси2 на своїй карті.
djkelly99

5
@Hendy Irawan: дозволені повторювані значення. Функція злиття полягає у виборі між (або злиттям) двох значень, які мають однаковий ключ .
Рікола

3
@ djkelly99 Насправді ви можете, вам просто потрібно повернути свою функцію перезавантаження null. Дивіться toMap doc, який вказує на об'єднання doc, який констатує Якщо функція перезавантаження повертає нуль, відображення видаляється.
Рікола

98

Як сказано в JavaDocs :

Якщо відображені ключі містять дублікати (згідно Object.equals(Object)), під IllegalStateExceptionчас виконання операції збору викидається а. Якщо відображені ключі можуть мати дублікати, використовуйте toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction)замість цього.

Тому слід використовувати toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction)замість цього. Просто надайте функцію злиття , яка визначатиме, який із дублікатів буде розміщено на карті.

Наприклад, якщо вам все одно, який саме, просто зателефонуйте

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

8

Відповідь @alaster мені дуже допомагає, але я хотів би додати значущу інформацію, якщо хтось намагається згрупувати її.

Якщо у вас, наприклад, два Ordersз однаковими, codeале різними quantityпродуктами для кожного, і ваше бажання підсумовує кількість, ви можете зробити:

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));

Результат:

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

1

Для групування за об'єктами

Map<Integer, Data> dataMap = dataList.stream().collect(Collectors.toMap(Data::getId, data-> data, (data1, data2)-> {LOG.info("Duplicate Group For :" + data2.getId());return data1;}));

1

Для всіх, хто отримує цю проблему, але без повторюваних дублікатів ключів на карті, переконайтеся, що функція keyMapper не повертає нульових значень .

Це дуже прикро відстежувати це, тому що помилка скаже «Дублікат ключа 1», коли 1 насправді є значенням запису замість ключа.

У моєму випадку моя функція keyMapper намагалася шукати значення на іншій карті, але через помилку друку в рядках повертала нульові значення.

final Map<String, String> doop = new HashMap<>();
doop.put("a", "1");
doop.put("b", "2");

final Map<String, String> lookup = new HashMap<>();
doop.put("c", "e");
doop.put("d", "f");

doop.entrySet().stream().collect(Collectors.toMap(e -> lookup.get(e.getKey()), e -> e.getValue()));

0

Я зіткнувся з такою проблемою під час групування об'єктів, я завжди вирішував їх простим способом: виконайте спеціальний фільтр, використовуючи java.util.Set, щоб видалити повторюваний об'єкт із будь-яким атрибутом на ваш вибір як нижче

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));

Сподіваюся, це допоможе кожному, хто має таку ж проблему!


-1

Припустимо, що у вас є люди - Список об’єктів

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

Тепер вам потрібно два кроки:

1)

people =removeDuplicate(people);

2)

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

Ось спосіб видалення дубліката

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;

      }

Додайте сюди повний приклад

 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 + "]";
    }

}

Результати:

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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.