Có cách nào tốt hơn để kết hợp hai bộ chuỗi trong java không?


90

Tôi cần kết hợp hai tập hợp chuỗi trong khi lọc ra thông tin dư thừa, đây là giải pháp mà tôi đã đưa ra, có cách nào tốt hơn mà bất cứ ai có thể đề xuất không? Có lẽ một cái gì đó được xây dựng trong đó mà tôi đã bỏ qua? Không có bất kỳ may mắn với google.

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

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

Câu trả lời:


116

Vì a Setkhông chứa các mục nhập trùng lặp, do đó bạn có thể kết hợp cả hai bằng cách:

newStringSet.addAll(oldStringSet);

Không thành vấn đề nếu bạn thêm mọi thứ hai lần, tập hợp sẽ chỉ chứa phần tử một lần ... ví dụ như không cần kiểm tra bằng containsphương thức.


88

Bạn có thể làm điều đó bằng cách sử dụng một lớp lót này

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

Với nhập tĩnh, nó trông đẹp hơn

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

Một cách khác là sử dụng phương pháp flatMap :

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

Ngoài ra, bất kỳ bộ sưu tập nào cũng có thể dễ dàng được kết hợp với một phần tử duy nhất

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

cái này tốt hơn addAll như thế nào?
KKlalala

7
@KKlalala, yêu cầu của bạn sẽ xác định cái nào tốt hơn. Sự khác biệt chính giữa addAllvà sử dụng Luồng là: • sử dụng set1.addAll(set2)sẽ có tác dụng phụ là thay đổi nội dung của set1. • Tuy nhiên, việc sử dụng Luồng sẽ luôn dẫn đến một thể hiện mới Setchứa nội dung của cả hai tập hợp mà không sửa đổi một trong các thể hiện Tập hợp ban đầu. IMHO câu trả lời này tốt hơn vì nó tránh các tác dụng phụ và khả năng thay đổi không mong muốn đối với bộ gốc nếu nó được sử dụng ở nơi khác trong khi mong đợi nội dung gốc. HTH
edwardsmatt

1
Điều này cũng có lợi thế là hỗ trợ các Bộ bất biến. Xem: docs.oracle.com/javase/8/docs/api/java/util/…
edwardsmatt

34

Tương tự với Ổi :

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

2
Sets :: union là một BinaryOperator tuyệt vời để sử dụng với Collectors.reducing ().
mskfisher

12

Từ định nghĩa Tập hợp chỉ chứa các phần tử duy nhất.

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

Để nâng cao mã của bạn, bạn có thể tạo một phương pháp chung cho

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

Nếu bạn đang sử dụng Guava, bạn cũng có thể sử dụng trình xây dựng để linh hoạt hơn:

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

4

Chỉ cần sử dụng newStringSet.addAll(oldStringSet). Không cần phải kiểm tra các bản sao vì việc Settriển khai đã làm được điều này.



3
 newStringSet.addAll(oldStringSet);

Điều này sẽ tạo ra Liên minh của s1 và s2


2

Sử dụng boolean addAll(Collection<? extends E> c)
Thêm tất cả các phần tử trong tập hợp được chỉ định vào tập hợp này nếu chúng chưa có mặt (thao tác tùy chọn). Nếu tập hợp được chỉ định cũng là một tập hợp, thì phép toán addAll sẽ sửa đổi tập hợp này một cách hiệu quả để giá trị của nó là hợp nhất của hai tập hợp. Hành vi của hoạt động này là không xác định nếu bộ sưu tập được chỉ định được sửa đổi trong khi hoạt động đang diễn ra.

newStringSet.addAll(oldStringSet)

2

Nếu bạn quan tâm đến hiệu suất và nếu bạn không cần giữ hai bộ của mình và một trong số chúng có thể lớn, tôi khuyên bạn nên kiểm tra bộ nào là lớn nhất và thêm các phần tử từ nhỏ nhất.

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

Bằng cách này, nếu tập hợp mới của bạn có 10 phần tử và tập hợp cũ của bạn có 100 000, bạn chỉ thực hiện 10 phép toán thay vì 100 000.


Đây là một logic rất tốt mà tôi không thể tưởng tượng được tại sao điều này không có trong phương pháp addAll parametter chính, nhưpublic boolean addAll(int index, Collection<? extends E> c, boolean checkSizes)
Gaspar

Tôi đoán vì bản thân đặc điểm kỹ thuật: Thêm tất cả các phần tử trong bộ sưu tập được chỉ định vào bộ sưu tập này . Bạn thực sự có thể có một phương thức khác nhưng sẽ khá khó hiểu nếu nó không tuân theo cùng một đặc điểm kỹ thuật với các phương thức mà nó quá tải.
Ricola

Vâng, tôi đang nói phương pháp quá tải khác mà một
Gaspar

2

Nếu bạn đang sử dụng Apache Common, hãy sử dụng SetUtilslớp từorg.apache.commons.collections4.SetUtils;

SetUtils.union(setA, setB);

Lưu ý rằng điều này trả về a SetView, là không thay đổi.
jaco0646

2
Set.addAll()

Thêm tất cả các phần tử trong tập hợp được chỉ định vào tập hợp này nếu chúng chưa có mặt (thao tác tùy chọn). Nếu tập hợp được chỉ định cũng là một tập hợp, thì phép toán addAll sẽ sửa đổi tập hợp này một cách hiệu quả để giá trị của nó là hợp nhất của hai tập hợp

newStringSet.addAll(oldStringSet)
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.