Java에서 두 개의 문자열 세트를 결합하는 더 좋은 방법이 있습니까?


90

중복 정보를 필터링하는 동안 두 개의 문자열 세트를 결합해야합니다. 이것이 제가 생각 해낸 해결책입니다. 누구든지 제안 할 수있는 더 좋은 방법이 있습니까? 내가 간과했던 내장 된 것이 아닐까요? Google에 운이 없었습니다.

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

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

답변:


116

a Set에는 중복 항목이 포함되어 있지 않으므로 다음과 같이 두 항목을 결합 할 수 있습니다.

newStringSet.addAll(oldStringSet);

두 번 추가해도 상관 없습니다. 세트에는 요소가 한 번만 포함됩니다. 예를 들어 contains메서드를 사용하여 확인할 필요가 없습니다 .


88

이 원 라이너로 할 수 있어요

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

정적 가져 오기를 사용하면 더 멋지게 보입니다.

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

또 다른 방법은 flatMap 메서드 를 사용 하는 것입니다.

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

또한 모든 컬렉션을 단일 요소로 쉽게 결합 할 수 있습니다.

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

이것이 addAll보다 나은 점은 무엇입니까?
KKlalala

7
@KKlalala, 귀하의 요구 사항에 따라 어느 것이 더 나은지 결정됩니다. addAllStreams를 사용하는 것과 사용 set1.addAll(set2)하는 것의 주요 차이점은 다음 과 같습니다. • using은의 내용을 물리적으로 변경하는 부작용이 있습니다 set1. • 그러나 Streams를 사용 Set하면 원래 Set 인스턴스 중 하나를 수정하지 않고 항상 두 집합의 내용을 포함 하는 새 인스턴스가 생성 됩니다. IMHO이 답변은 원래 내용을 기대하면서 다른 곳에서 사용되는 경우 부작용과 원래 세트에 대한 예기치 않은 변경 가능성을 피하기 때문에 더 좋습니다. HTH
edwardsmatt

1
이것은 또한 불변 집합을 지원하는 장점이 있습니다. 참조 : docs.oracle.com/javase/8/docs/api/java/util/…
edwardsmatt

34

Guava 와 동일 :

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

2
Sets :: union은 Collectors.reducing ()과 함께 사용할 수있는 훌륭한 BinaryOperator입니다.
mskfisher

12

정의 세트에서 고유 한 요소 만 포함합니다.

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

코드를 향상시키기 위해 일반적인 방법을 만들 수 있습니다.

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

Guava를 사용하는 경우 빌더를 사용하여 더 많은 유연성을 얻을 수도 있습니다.

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

4

그냥 사용하십시오 newStringSet.addAll(oldStringSet). Set구현에서 이미 수행 하므로 중복을 확인할 필요가 없습니다 .



3
 newStringSet.addAll(oldStringSet);

이것은 s1과 s2의 결합을 생성합니다.


2

사용 boolean addAll(Collection<? extends E> c)
지정된 컬렉션의 모든 요소가 아직없는 경우이 집합에 추가합니다 (선택적 작업). 지정된 컬렉션도 집합 인 경우 addAll 작업은 해당 값이 두 집합의 합집합이되도록이 집합을 효과적으로 수정합니다. 작업이 진행중인 동안 지정된 컬렉션이 수정되면이 작업의 동작은 정의되지 않습니다.

newStringSet.addAll(oldStringSet)

2

성능에 관심이 있고 두 세트를 유지할 필요가없고 그중 하나가 클 수 있다면 어떤 세트가 가장 큰지 확인하고 가장 작은 요소를 추가하는 것이 좋습니다.

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

이런 식으로 새 세트에 10 개의 요소가 있고 이전 세트에 100,000 개가있는 경우 100,000 개 대신 10 개의 작업 만 수행합니다.


이것은 내가 왜 이것이 주 addAll 메소드 매개 변수에 없는지 상상할 수없는 아주 좋은 논리입니다.public boolean addAll(int index, Collection<? extends E> c, boolean checkSizes)
Gaspar

사양 자체 때문에 추측 합니다. 지정된 컬렉션의 모든 요소를이 컬렉션에 추가 합니다. 실제로 다른 방법을 사용할 수 있지만 오버로드하는 방법과 동일한 사양을 따르지 않으면 매우 혼란 스러울 것입니다.
Ricola

그래, 내가 말한 다른 방법 오버로드 하나
가스파

2

Apache Common을 사용하는 경우 다음 SetUtils에서 클래스를 사용하십시오.org.apache.commons.collections4.SetUtils;

SetUtils.union(setA, setB);

이것은 SetView변경 불가능한를 반환합니다 .
jaco0646

2
Set.addAll()

지정된 컬렉션의 모든 요소가 아직없는 경우이 집합에 추가합니다 (선택적 작업). 지정된 컬렉션도 집합 인 경우 addAll 작업은 해당 값이 두 집합의 합집합이되도록이 집합을 효과적으로 수정합니다.

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