Akışları kullanarak harita oluştururken kopyaları yoksay


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

java.lang.IllegalStateException: Duplicate keyÇoğaltılmış bir eleman bulunduğunda anlıyorum .

Haritaya değer ekleme konusundaki bu istisnayı göz ardı etmek mümkün müdür?

Yinelenen varsa, yinelenen anahtarı yok sayarak devam etmelidir.


Kullanabiliyorsanız, HashSet zaten varsa anahtarı yok sayar.
sahitya

@ Kaptan-Aryabhata. Hashset'te anahtar değerlere sahip olmak mümkün mü
Patan

Yanıtlar:


449

Bu, aşağıdaki mergeFunctionparametreler kullanılarak mümkündür 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;
             }
          ));

mergeFunctionaynı tuşla ilişkilendirilmiş iki değer üzerinde çalışan bir işlevdir. adress1elemanlar toplanırken karşılaşılan ilk adrese ve adress2karşılaşılan ikinci adrese karşılık gelir: bu lambda sadece ilk adresi tutmayı söyler ve ikinciyi yok sayar.


6
Kafam karıştı, neden yinelenen değerlere (anahtarlara değil) izin verilmiyor? Ve yinelenen değerlere nasıl izin verilir?
Hendy Irawan

çarpışmanın gerçekleştiği anahtarı almanın bir yolu var mı? burada cevap verin: stackoverflow.com/questions/40761954/…
Guillaume

2
Bir çatışma olursa bu girişi tamamen göz ardı etmek mümkün müdür? Temel olarak, yinelenen anahtarlarla karşılaşırsam bunların eklenmesini hiç istemiyorum. Yukarıdaki örnekte, haritamda adres1 veya adres2'yi istemiyorum.
djkelly99

5
@Hendy Irawan: Yinelenen değerlere izin verilir. Birleştirme işlevi, aynı tuşa sahip iki değer arasında seçim yapmak (veya birleştirmek) içindir .
Ricola

3
@ djkelly99 Aslında, yeniden eşleme fonksiyonunuzun geri dönmesini sağlamanız yeterlidir null. Bkz tomap doc gelin bu birleştirme doc bildiren yeniden eşleme işlevin döndürdüğü boş ise eşleştirme kaldırılır.
Ricola

98

As söyledi javadocs :

Eşlenen tuşlar yinelenen (buna göre Object.equals(Object)) içeriyorsa IllegalStateException, toplama işlemi gerçekleştirildiğinde a atılır. Eşlenen anahtarlarda kopyalar varsa toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction)bunun yerine kullanın.

Onun toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction)yerine kullanmalısınız . Yinelenenlerden hangisinin haritaya yerleştirileceğini belirleyen bir birleştirme işlevi sağlamanız yeterlidir .

Örneğin, hangisini umursamıyorsanız, sadece

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

8

@Alaster yanıtı bana çok yardımcı oluyor, ancak birisi bilgileri gruplandırmaya çalışıyorsa anlamlı bir bilgi eklemek istiyorum.

Eğer varsa, örneğin başına, iki Ordersaynı olan codefakat farklı quantityher biri için ürünlerin ve arzu olduğunu Özetle , yapabileceğiniz miktarlarda:

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

Sonuç:

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

2

Bu sorunu alan ancak haritadaki yinelenen anahtarlar yayınlanmayan herkes için keyMapper işlevinizin boş değerler döndürmediğinden emin olun .

Bunu takip etmek çok can sıkıcıdır çünkü 1 aslında anahtar yerine girişin değeri olduğunda hata "Yinelenen anahtar 1" diyecektir .

Benim durumumda, keyMapper işlevim farklı bir haritadaki değerleri aramaya çalıştı, ancak dizelerdeki yazım hatası nedeniyle boş değerler döndürüyordu.

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

1

Nesnelere göre gruplama için

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

0

Nesneyi gruplarken böyle bir sorunla karşılaştım, her zaman basit bir yolla çözdüm: java.util.Set kullanarak özel bir filtre gerçekleştirin, seçtiğiniz nesneyle feryat olarak istediğiniz nesneyi kaldırmak için

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

Umarım bu aynı problemi olan herkese yardımcı olur!


-1

Kişi olduğunu varsayalım Nesne Listesi

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

Şimdi iki adıma ihtiyacınız var:

1)

people =removeDuplicate(people);

2)

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

İşte yinelenen kaldırmak için yöntem

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;

      }

Buraya tam örnek ekleme

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

}

Sonuçlar :

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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.