ProgramingTip

두 목록 비교

bestdevel 2020. 12. 3. 08:15
반응형

두 목록 비교 평등을 위해


요소를 하나씩 단계별로 실행하는 것 외에 두 개의 목록이 같은지하는 방법 (.NET 3.0에서) :

이것은 실패합니다.

// Expected result.
List<string> expected = new List<string>();
expected.Add( "a" );
expected.Add( "b" );
expected.Add( "c" );

// Actual result
actual = new List<string>();
actual.Add( "a" );
actual.Add( "b" );
actual.Add( "c" );

// Verdict
Assert.IsTrue( actual == expected );

많은 테스트 프레임 워크가 CollectionAssert 클래스를 제공합니다.

CollectionAssert.AreEqual(expected, actual);

예 : MS 테스트


다음을 시도하십시오

var equal = expected.SequenceEqual(actual);

테스트 버전

Assert.IsTrue( actual.SequenceEqual(expected) );

SequenceEqual 확장 메서드는 동일성을 위해 컬렉션의 요소를 비교합니다.

http://msdn.microsoft.com/en-us/library/bb348567(v=vs.100).aspx 참조


언제든지 필요한 함수를 직접 작성할 수 있습니다.

public static bool ListEquals<T>(IList<T> list1, IList<T> list2) {
    if (list1.Count != list2.Count)
        return false;
    for (int i = 0; i < list1.Count; i++)
        if (!list1[i].Equals(list2[i]))
            return false;
    return true;
}

그리고 그것을 사용하십시오 :

// Expected result.
List<string> expected = new List<string>();
expected.Add( "a" );
expected.Add( "b" );
expected.Add( "c" );

// Actual result
actual = new List<string>();
actual.Add( "a" );
actual.Add( "b" );
actual.Add( "c" );

// Verdict
Assert.IsTrue( ListEquals(actual, expected) );

원래 코드가 작동하지 않는 이유를 알리지 않습니다. 이는 ==일반 테스트 의 연산자가 연산자가 오버로드 되지 않는 한 동등성을 참조 하기 때문입니다 (즉, 두 인스턴스가 메모리에서 인스턴스를 표현하는 경우) . 연산자를 정의하지 않으면 기본 참조가 구현과 동일합니다.List<T>==

다른 포스터가 시연했듯이 일반적으로 "컬렉션 평등"을 테스트하기 위해 요소를 단계별로 진행해야합니다. 물론 컬렉션을 단계별로 진행하기 전에 먼저 컬렉션 ​​개수를 테스트하는 사용자 DreamWalker제안한 최적화를 합니다.


주문이 중요한 경우 :

bool equal = a.SequenceEquals(b);

주문이 중요하지 않은 경우 :

bool equal = a.Count == b.Count && new HashSet<string>(a).SetEquals(b);

다음과 같이 확장 메서드를 사용할 수 있습니다.

public static class ListExtensions
    {
        public static bool IsEqual<T>(this IList<T> list,IList<T> target, IComparer<T> comparer) where T:IComparable<T>
        {
            if (list.Count != target.Count)
            {
                return false;
            }
            int index = 0;
            while (index < list.Count && 
                   comparer.Compare(list[index],target[index]) == 0)
            {
                index++;
            }
            if (index != list.Count)
            {
                return false;
            }
            return true;
        }
    }

그리고 그렇게 부르십시오.

List<int> intList = new List<int> { 1, 234, 2, 324, 324, 2 };
List<int> targetList = new List<int> { 1, 234, 2, 324, 324 };
bool isEqual = intList.IsEqual(targetList, Comparer<int>.Default);

편집 : OP가 .NET 3.0을 사용하기 때문에 대신 정적 메서드를 사용하도록 코드를 업데이트했습니다.

public static bool IsEqual<T>(IList<T> sourceList, IList<T> targetList, IComparer<T> comparer) where T : IComparable<T>
        {
            if (sourceList.Count != targetList.Count)
            {
                return false;
            }
            int index = 0;
            while (index < sourceList.Count &&
                   comparer.Compare(sourceList[index], targetList[index]) == 0)
            {
                index++;
            }
            if (index != sourceList.Count)
            {
                return false;
            }
            return true;
        }

고객 :

        bool isEqual = IsEqual(intList,targetList, Comparer<int>.Default);

Linq를 사용하고 코드를 확장 메소드로 작성 :

public static bool EqualsOtherList<T>(this List<T> thisList, List<T> theOtherList)
{
  if (thisList == null || theOtherList == null || 
      thisList.Count != theOtherList.Count) return false;
  return !thisList.Where((t, i) => !t.Equals(theOtherList[i])).Any();
}

컬렉션을 반복하는 동안 내가 만든이 확장 방법은 두 목록의 순서가 같을 필요가 있으며 동등한 방법이 재정의 한 복잡한 형식을 작동합니다.

다음 두 목록은 true를 반환합니다.

List<string> list1 = new List<string>
{
    { "bob" },
    { "sally" },
    { "john" }
};

List<string> list2 = new List<string>
{
    { "sally" },
    { "john" },
    { "bob" }
};

방법 :

public static bool IsEqualTo<T>(this IList<T> list1, IList<T> list2)
{
    if (list1.Count != list2.Count)
    {
        return false;
    }

    List<T> list3 = new List<T>();

    foreach (var item in list2)
    {
        list3.Add(item);
    }

    foreach (var item in list1)
    {
        int index = -1;
        for (int x = 0; x < list3.Count; x++)
        {
            if (list3[x].Equals(item))
            {
                index = x;
            }
        }

        if (index > -1)
        {
            list3.RemoveAt(index);
        }
        else
        {
            return false;
        }
    }

    return !list3.Any();
}

규칙적인 방법이 아닌 사용자 정의 유형에 대한 IEquatable 구현없이 사용할 수 있습니다.

JsonConvert.SerializeObject( myList1) == JsonConvert.SerializeObject( myList2)

그러나 일반적으로 https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.sequenceequal?view=netframework-4.8 주석에 언급 된대로 SequenceEqual을 사용할 수 있습니다.

또한 사용자 정의 유형에 대한 IEquatable 인터페이스를 구현하는 것을 잊지 않고 (문자열 유형 또는 기타 구조에는 필요하지 않습니다).

참고 URL : https://stackoverflow.com/questions/1546925/comparing-two-liststring-for-equality

반응형