스트림을 사용하여 맵을 생성 할 때 중복 무시


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

java.lang.IllegalStateException: Duplicate key중복 요소가 발견되면 얻습니다 .

지도에 값을 추가 할 때 이러한 예외를 무시할 수 있습니까?

중복이 있으면 중복 키를 무시하여 계속 진행해야합니다.


사용할 수 있으면 HashSet은 해당 키가 이미있는 경우 해당 키를 무시합니다.
sahitya

@ captain-aryabhatta. 해시 셋에서 키 값을 가질 수 있습니까
Patan

답변:


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
혼란 스럽습니다. 왜 키가 아닌 중복 값이 허용되지 않습니까? 중복 값을 허용하는 방법은 무엇입니까?
Hendy Irawan

충돌이 발생한 키를 검색하는 방법이 있습니까? 여기에 답변하십시오 : stackoverflow.com/questions/40761954/…
Guillaume

2
충돌이있는 경우이 항목을 완전히 무시할 수 있습니까? 기본적으로 중복 키가 발생하면 키를 전혀 추가하고 싶지 않습니다. 위의 예에서지도에 address1 또는 address2를 원하지 않습니다.
djkelly99

5
@Hendy Irawan : 중복 값이 ​​허용됩니다. 병합 기능은 동일한 키가진 두 값 중에서 선택하거나 병합 합니다 .
Ricola

3
@ djkelly99 실제로 당신은 당신의 리매핑 함수를 return 시켜야만한다 null. 참조 toMap의 문서 를 가리 병합 문서는 국가는 다시 매핑 함수가 리턴 null의 경우, 매핑이 제거됩니다.
Ricola

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 함수가 null 값을 반환하지 않는지 확인하십시오 .

1이 실제로 값일 때 오류에 "중복 키 1"이 표시되므로이를 추적하는 것은 매우 성가시다. 키 대신 항목 .

필자의 경우 keyMapper 함수가 다른 맵에서 값을 찾으려고했지만 문자열의 오타로 인해 null 값이 반환되었습니다.

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)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.