Apakah ada cara yang lebih baik untuk menggabungkan dua set string di java?


90

Saya perlu menggabungkan dua set string sambil menyaring informasi yang berlebihan, ini adalah solusi yang saya buat, adakah cara yang lebih baik yang dapat disarankan oleh siapa pun? Mungkin sesuatu yang dibangun di dalamnya saya abaikan? Tidak beruntung dengan google.

Set<String> oldStringSet = getOldStringSet();
Set<String> newStringSet = getNewStringSet();

for(String currentString : oldStringSet)
{
    if (!newStringSet.contains(currentString))
    {
        newStringSet.add(currentString);
    }
}

Jawaban:


116

Karena a Settidak berisi entri duplikat, Anda dapat menggabungkan keduanya dengan:

newStringSet.addAll(oldStringSet);

Tidak masalah jika Anda menambahkan sesuatu dua kali, set hanya akan berisi elemen satu kali ... misalnya tidak perlu memeriksa menggunakan containsmetode.


88

Anda dapat melakukannya menggunakan satu baris ini

Set<String> combined = Stream.concat(newStringSet.stream(), oldStringSet.stream())
        .collect(Collectors.toSet());

Dengan impor statis, tampilannya bahkan lebih bagus

Set<String> combined = concat(newStringSet.stream(), oldStringSet.stream())
        .collect(toSet());

Cara lain adalah dengan menggunakan metode flatMap :

Set<String> combined = Stream.of(newStringSet, oldStringSet).flatMap(Set::stream)
        .collect(toSet());

Koleksi apapun juga dapat dengan mudah digabungkan dengan satu elemen

Set<String> combined = concat(newStringSet.stream(), Stream.of(singleValue))
        .collect(toSet());

bagaimana ini lebih baik dari addAll?
KKlalala

7
@KKlalala, persyaratan Anda akan menentukan mana yang lebih baik. Perbedaan utama antara addAlldan menggunakan Stream adalah: • menggunakan set1.addAll(set2)akan memiliki efek samping mengubah konten secara fisik set1. • Namun, menggunakan Streams akan selalu menghasilkan instance baru yang Setberisi konten dari kedua set tanpa mengubah salah satu instance Set asli. IMHO jawaban ini lebih baik karena menghindari efek samping dan potensi perubahan tak terduga ke set asli jika itu akan digunakan di tempat lain sambil mengharapkan konten asli. HTH
edwardsmatt

1
Ini juga memiliki keuntungan dalam mendukung Immutable Sets. Lihat: docs.oracle.com/javase/8/docs/api/java/util/…
edwardsmatt

34

Sama dengan Jambu Biji :

Set<String> combinedSet = Sets.union(oldStringSet, newStringSet)

2
Sets :: union adalah BinaryOperator yang bagus untuk digunakan dengan Collectors.reducing ().
mskfisher

12

Dari definisi Set hanya berisi elemen unik.

Set<String> distinct = new HashSet<String>(); 
 distinct.addAll(oldStringSet);
 distinct.addAll(newStringSet);

Untuk meningkatkan kode Anda, Anda dapat membuat metode umum untuk itu

public static <T> Set<T> distinct(Collection<T>... lists) {
    Set<T> distinct = new HashSet<T>();

    for(Collection<T> list : lists) {
        distinct.addAll(list);
    }
    return distinct;
}

6

Jika Anda menggunakan Guava, Anda juga dapat menggunakan builder untuk mendapatkan lebih banyak fleksibilitas:

ImmutableSet.<String>builder().addAll(someSet)
                              .addAll(anotherSet)
                              .add("A single string")
                              .build();

4

Gunakan saja newStringSet.addAll(oldStringSet). Tidak perlu memeriksa duplikat karena Setimplementasi sudah melakukannya.



3
 newStringSet.addAll(oldStringSet);

Ini akan menghasilkan Union s1 dan s2


2

Gunakan boolean addAll(Collection<? extends E> c)
Tambahkan semua elemen dalam koleksi yang ditentukan ke set ini jika mereka belum ada (operasi opsional). Jika koleksi yang ditentukan juga merupakan satu set, operasi addAll secara efektif mengubah set ini sehingga nilainya adalah gabungan dari dua set. Perilaku operasi ini tidak ditentukan jika koleksi yang ditentukan diubah saat operasi sedang berlangsung.

newStringSet.addAll(oldStringSet)

2

Jika Anda peduli dengan kinerja, dan jika Anda tidak perlu menyimpan dua set Anda dan salah satunya bisa sangat besar, saya sarankan untuk memeriksa set mana yang terbesar dan menambahkan elemen dari yang terkecil.

Set<String> newStringSet = getNewStringSet();
Set<String> oldStringSet = getOldStringSet();

Set<String> myResult;
if(oldStringSet.size() > newStringSet.size()){
    oldStringSet.addAll(newStringSet);
    myResult = oldStringSet;
} else{
    newStringSet.addAll(oldStringSet);
    myResult = newStringSet;
}

Dengan cara ini, jika set baru Anda memiliki 10 elemen dan set lama Anda memiliki 100.000, Anda hanya melakukan 10 operasi, bukan 100.000.


Ini adalah logika yang sangat bagus yang saya tidak bisa membayangkan mengapa ini tidak ada di parameter metode addAll utama, sepertipublic boolean addAll(int index, Collection<? extends E> c, boolean checkSizes)
Gaspar

Saya rasa karena spesifikasinya sendiri: Menambahkan semua elemen dalam koleksi yang ditentukan ke koleksi ini . Anda memang dapat memiliki metode lain tetapi akan sangat membingungkan jika tidak mengikuti spesifikasi yang sama dengan metode yang dilebih-lebihkan.
Ricola

Ya, saya mengatakan metode lain membebani yang satu itu
Gaspar

2

Jika Anda menggunakan Apache Common, gunakan SetUtilskelas dariorg.apache.commons.collections4.SetUtils;

SetUtils.union(setA, setB);

Perhatikan bahwa ini mengembalikan a SetView, yang tidak dapat diubah.
jaco0646

2
Set.addAll()

Menambahkan semua elemen dalam koleksi yang ditentukan ke set ini jika belum ada (operasi opsional). Jika koleksi yang ditentukan juga merupakan satu set, operasi addAll secara efektif mengubah set ini sehingga nilainya adalah gabungan dari dua set

newStringSet.addAll(oldStringSet)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.