Bỏ qua các bản sao khi tạo bản đồ bằng luồng


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

Tôi nhận được java.lang.IllegalStateException: Duplicate keykhi một yếu tố trùng lặp được tìm thấy.

Có thể bỏ qua ngoại lệ như vậy khi thêm giá trị vào bản đồ?

Khi có trùng lặp, chỉ cần tiếp tục bằng cách bỏ qua khóa trùng lặp đó.


Nếu bạn có thể sử dụng nó, Hashset sẽ bỏ qua khóa, nếu nó đã tồn tại.
sahitya

@ đội trưởng-aryabhatta. Có thể có các giá trị chính trong hashset
Patan

Câu trả lời:


449

Điều này có thể sử dụng mergeFunctiontham số của 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;
             }
          ));

mergeFunctionlà một hàm hoạt động trên hai giá trị được liên kết với cùng một khóa. adress1tương ứng với địa chỉ đầu tiên gặp phải khi thu thập các phần tử và adress2tương ứng với địa chỉ thứ hai gặp phải: lambda này chỉ bảo giữ địa chỉ đầu tiên và bỏ qua địa chỉ thứ hai.


5
Tôi bối rối, tại sao các giá trị trùng lặp (không phải khóa) không được phép? Và làm thế nào để cho phép các giá trị trùng lặp?
Hendy I Girls

Có cách nào để lấy chìa khóa mà xảy ra va chạm không? trả lời tại đây: stackoverflow.com/questions / 40761954 / từ
Guillaume

2
Có thể hoàn toàn bỏ qua mục này nếu có xung đột? Về cơ bản, nếu tôi gặp phải các khóa trùng lặp, tôi không muốn thêm chúng vào. Trong ví dụ trên, tôi không muốn address1 hoặc address2 trong bản đồ của mình.
djkelly99

5
@Hendy IINA: giá trị trùng lặp được cho phép. Hàm hợp nhất là chọn giữa (hoặc hợp nhất) hai giá trị có cùng khóa .
Ricola

3
@ djkelly99 Thật ra bạn có thể, bạn chỉ cần làm cho chức năng ánh xạ lại của bạn trở lại null. Xem tài liệu toMap trỏ đến hợp nhất tài liệu trạng thái Nếu hàm ánh xạ trả về null, ánh xạ sẽ bị xóa.
Ricola

98

Như đã nói trong JavaDocs :

Nếu các khóa được ánh xạ chứa các bản sao (theo Object.equals(Object)), một IllegalStateExceptionsẽ được ném khi thao tác thu thập được thực hiện. Nếu các phím được ánh xạ có thể có trùng lặp, sử dụng toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction)thay thế.

Vì vậy, bạn nên sử dụng toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction)thay thế. Chỉ cần cung cấp một hàm hợp nhất , điều đó sẽ xác định một trong những bản sao được đặt trong bản đồ.

Ví dụ: nếu bạn không quan tâm cái nào, chỉ cần gọi

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

8

Câu trả lời @alaster giúp tôi rất nhiều, nhưng tôi muốn thêm một thông tin có ý nghĩa nếu ai đó đang cố gắng nhóm thông tin.

Nếu bạn có, ví dụ, hai sản phẩm Orderscó cùng loại codenhưng khác nhau quantitycho mỗi sản phẩm và mong muốn của bạn là tổng số lượng, bạn có thể làm:

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

Kết quả:

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

1

Để nhóm theo đối tượng

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

Đối với bất kỳ ai khác gặp phải vấn đề này nhưng không có các khóa trùng lặp trong bản đồ được truyền phát, hãy đảm bảo rằng hàm keyMapper của bạn không trả về giá trị null .

Thật khó chịu khi theo dõi điều này vì lỗi sẽ nói "Khóa trùng lặp 1" khi 1 thực sự là giá trị của mục nhập thay vì khóa.

Trong trường hợp của tôi, hàm keyMapper của tôi đã cố gắng tìm kiếm các giá trị trong một bản đồ khác, nhưng do một lỗi đánh máy trong chuỗi đã trả về giá trị 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

Tôi đã gặp phải một vấn đề như vậy khi nhóm đối tượng, tôi luôn giải quyết chúng bằng một cách đơn giản: thực hiện bộ lọc tùy chỉnh bằng java.util.Set để xóa đối tượng trùng lặp với bất kỳ thuộc tính nào bạn chọn dưới đây

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

Hy vọng điều này sẽ giúp bất cứ ai có cùng một vấn đề!


-1

Giả sử bạn có người là Danh sách đối tượng

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

Bây giờ bạn cần hai bước:

1)

people =removeDuplicate(people);

2)

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

Đây là phương pháp để loại bỏ trùng lặp

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;

      }

Thêm ví dụ đầy đủ ở đây

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

}

Các kết quả :

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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.