it-swarm.com.ru

Игнорировать дубликаты при создании карты с использованием потоков

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

Я получаю исключение дубликата ключа при возникновении дубликатов. 

Можно ли игнорировать добавление значений на карту при возникновении дубликатов?

Когда есть дубликат, он просто должен продолжаться, игнорируя этот дубликат ключа.

168
Patan

Это возможно с помощью параметра 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 соответствует второму обнаруженному адресу: эта лямбда-команда просто указывает сохранить первый адрес и игнорирует второй.

311
Tunaki

Как сказано в 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, (p1, p2) -> p1));
65
alaster

Я столкнулся с такой проблемой при группировке объектов, я всегда разрешал их простым способом: выполнял пользовательский фильтр с помощью 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));

Надеюсь, это поможет всем, у кого возникла такая же проблема!

0
Shessuky

Ответ @alaster мне очень помогает, но я хотел бы добавить содержательную информацию, если кто-то пытается сгруппировать информацию.

Если у вас есть, например, два Orders с одинаковым code, но разными quantity продуктами для каждого, и вы хотите sumколичества, вы можете сделать:

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}
0
Dherik

Предполагая, что у вас есть люди, список объектов 

  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)
0
vaquar khan