Linq의 Union Vs Concat


86

Union및에 대한 질문이 있습니다 Concat. 두 경우 모두 동일하게 행동한다고 ​​생각합니다 List<T>.

var a1 = (new[] { 1, 2 }).Union(new[] { 1, 2 });             // O/P : 1 2
var a2 = (new[] { 1, 2 }).Concat(new[] { 1, 2 });            // O/P : 1 2 1 2

var a3 = (new[] { "1", "2" }).Union(new[] { "1", "2" });     // O/P : "1" "2"
var a4 = (new[] { "1", "2" }).Concat(new[] { "1", "2" });    // O/P : "1" "2" "1" "2"

위의 결과가 예상됩니다.

하지만 List<T>같은 결과를 얻고 있다면 .

class X
{
    public int ID { get; set; }
}

class X1 : X
{
    public int ID1 { get; set; }
}

class X2 : X
{
    public int ID2 { get; set; }
}

var lstX1 = new List<X1> { new X1 { ID = 10, ID1 = 10 }, new X1 { ID = 10, ID1 = 10 } };
var lstX2 = new List<X2> { new X2 { ID = 10, ID2 = 10 }, new X2 { ID = 10, ID2 = 10 } };

var a5 = lstX1.Cast<X>().Union(lstX2.Cast<X>());     // O/P : a5.Count() = 4
var a6 = lstX1.Cast<X>().Concat(lstX2.Cast<X>());    // O/P : a6.Count() = 4

그러나 두 가지 모두 List<T>.

어떤 제안을 부탁드립니다.


1
이 두 가지 방법의 차이점을 알고 있다면 그 결과가 왜 당신을 놀라게할까요? 메서드 기능의 직접적인 결과입니다.
Konrad Rudolph 2011

@KonradRudolph, List <T>의 경우 'Union'/ 'Concat'중 하나를 사용할 수 있습니다. 둘 다 동일하게 행동하기 때문입니다.
Prasad Kanaparthi

아니, 당연하지. 첫 번째 예에서 볼 수 있듯이 동일하게 작동하지 않습니다.
Konrad Rudolph 2012

귀하의 예에서는 모든 ID가 다릅니다.
Jim Mischel 2012

@JimMischel, 내 게시물을 수정했습니다. 동일한 값으로도 동일하게 작동합니다.
Prasad Kanaparthi

답변:


110

Union은 Distinct값을 반환 합니다. 기본적으로 항목의 참조를 비교합니다. 항목에 다른 참조가 있으므로 모두 다른 것으로 간주됩니다. 기본 유형으로 캐스트하면 X참조가 변경되지 않습니다.

EqualsGetHashCode(고유 항목을 선택하는 데 사용됨)을 재정의하면 항목이 참조로 비교되지 않습니다.

class X
{
    public int ID { get; set; }

    public override bool Equals(object obj)
    {
        X x = obj as X;
        if (x == null)
            return false;
        return x.ID == ID;
    }

    public override int GetHashCode()
    {
        return ID.GetHashCode();
    }
}

그러나 모든 항목의 값은 ID. 따라서 모든 항목은 여전히 ​​다른 것으로 간주됩니다. 이 같은 여러 항목을 제공 할 것입니다 경우 ID당신은 차이 볼 UnionConcat:

var lstX1 = new List<X1> { new X1 { ID = 1, ID1 = 10 }, 
                           new X1 { ID = 10, ID1 = 100 } };
var lstX2 = new List<X2> { new X2 { ID = 1, ID2 = 20 }, // ID changed here
                           new X2 { ID = 20, ID2 = 200 } };

var a5 = lstX1.Cast<X>().Union(lstX2.Cast<X>());  // 3 distinct items
var a6 = lstX1.Cast<X>().Concat(lstX2.Cast<X>()); // 4

정수는 값 유형이고 값으로 비교되기 때문에 초기 샘플이 작동합니다.


3
참조를 비교하지 않고 예를 들어 내부의 ID를 비교하더라도 ID가 다르기 때문에 여전히 4 개의 항목이 있습니다.
Rawling 2011

@Swani nope, 그들은 아닙니다. 내가 위에서 언급 한대로, 두 번째 컬렉션의 첫 번째 항목의 ID를 변경하지 않았다고 생각
세르게이 Berezovskiy

@Swani 그러면 위에서 언급했듯이 Equals 및 GetHashCode를 재정의하지 않았습니다
Sergey Berezovskiy

@lazyberezovsky, 나는 당신의 대답에 동의합니다. 그러나 나는 여전히 의견에 만족하지 않습니다. 내 샘플 코드를 실행하면 'a5'와 'a6'에 대해 동일한 결과를 볼 수 있습니다. 나는 해결책을 찾고 있지 않습니다. 하지만 왜 'Concat'과 'Union'이 그 sistuation에서 동일하게 행동하는지. 답장 해주세요.
Prasad Kanaparthi

3
@Swani 죄송합니다, afk. x.Union(y)와 동일합니다 x.Concat(y).Distinct(). 따라서 차이점은 Distinct. Linq는 연결된 시퀀스에서 고유 한 (즉, 다른) 개체를 어떻게 선택합니까? 샘플 코드 (질문에서)에서 Linq는 참조 (즉, 메모리의 주소)로 객체를 비교합니다. new연산자 를 통해 새 객체를 생성하면 새 주소에 메모리를 할당합니다. 따라서 새로 생성 된 개체가 4 개 있으면 주소가 달라집니다. 그리고 모든 물체는 구별됩니다. 따라서 Distinct시퀀스에서 모든 개체를 반환합니다.
Sergey Berezovskiy 2011

48

Concat말 그대로 첫 번째 시퀀스의 항목과 두 번째 시퀀스의 항목을 반환합니다. Concat두 개의 2- 항목 시퀀스에 사용 하는 경우 항상 4- 항목 시퀀스를 얻습니다.

Union본질적으로 Concat뒤에 Distinct.

처음 두 경우에는 두 개의 항목 시퀀스로 끝납니다. 그 사이에 각 입력 squence 쌍에는 정확히 두 개의 개별 항목이 있기 때문입니다.

세 번째 경우 두 입력 시퀀스의 4 개 항목이 모두 구별 되기 때문에 4 개 항목 시퀀스로 끝납니다 .


14

UnionConcat같은 동작합니다 때문에 Union사용자 정의없이 중복을 감지 할 수 없습니다 IEqualityComparer<X>. 둘 다 동일한 참조인지 확인하는 것입니다.

public class XComparer: IEqualityComparer<X>
{
    public bool Equals(X x1, X x2)
    {
        if (object.ReferenceEquals(x1, x2))
            return true;
        if (x1 == null || x2 == null)
            return false;
        return x1.ID.Equals(x2.ID);
    }

    public int GetHashCode(X x)
    {
        return x.ID.GetHashCode();
    }
}

이제 다음의 오버로드에서 사용할 수 있습니다 Union.

var comparer = new XComparer();
a5 = lstX1.Cast<X>().Union(lstX2.Cast<X>(), new XComparer()); 
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.