문제

내 Equals 메서드에서 두 컬렉션의 내용을 비교하고 싶습니다.사전과 IList가 있습니다.이를 수행하는 기본 제공 방법이 있습니까?

편집됨:두 개의 사전과 두 개의 IList를 비교하고 싶기 때문에 동등성이 무엇을 의미하는지 분명하다고 생각합니다. 두 사전에 동일한 값에 매핑된 동일한 키가 포함되어 있으면 두 사전은 동일합니다.

도움이 되었습니까?

해결책

Enumerable.SequenceEqual

지정된 IEqualityComparer(T)를 사용하여 해당 요소를 비교하여 두 시퀀스가 ​​동일한지 여부를 확인합니다.

목록과 사전을 직접 비교할 수는 없지만 사전의 값 목록을 목록과 비교할 수 있습니다.

다른 팁

다른 사람들이 제안하고 지적했듯이, SequenceEqual 순서에 민감합니다.이 문제를 해결하려면 키(고유하므로 정렬이 항상 안정적임)를 기준으로 사전을 정렬한 다음 다음을 사용할 수 있습니다. SequenceEqual.다음 표현식은 내부 순서에 관계없이 두 사전이 동일한지 확인합니다.

dictionary1.OrderBy(kvp => kvp.Key).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key))

편집하다: Jeppe Stig Nielsen이 지적했듯이 일부 개체에는 IComparer<T> 그것은 그들의 것과 호환되지 않습니다 IEqualityComparer<T>, 잘못된 결과가 나타납니다.이러한 객체에 키를 사용할 때는 올바른 키를 지정해야 합니다. IComparer<T> 그 열쇠를 위해.예를 들어, 문자열 키(이 문제가 발생함)를 사용하는 경우 올바른 결과를 얻으려면 다음을 수행해야 합니다.

dictionary1.OrderBy(kvp => kvp.Key, StringComparer.Ordinal).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key, StringComparer.Ordinal))

언급된 것 외에도 시퀀스Equal, 어느

두 목록이 길이가 같고 해당 요소가 비교에 따라 동일하게 비교하면 사실입니다.

(이는 기본 비교자일 수 있습니다. 즉,재정의된 Equals())

.Net4에는 다음이 있다는 점을 언급할 가치가 있습니다. SetEquals ~에 ISet 물체

요소의 순서와 중복 요소를 무시합니다.

따라서 개체 목록을 갖고 싶지만 특정 순서로 정렬할 필요는 없다면 다음을 고려하세요. ISet (같은 HashSet)가 올바른 선택일 수 있습니다.

다음을 살펴보세요. 열거 가능.SequenceEqual 방법

var dictionary = new Dictionary<int, string>() {{1, "a"}, {2, "b"}};
var intList = new List<int> {1, 2};
var stringList = new List<string> {"a", "b"};
var test1 = dictionary.Keys.SequenceEqual(intList);
var test2 = dictionary.Values.SequenceEqual(stringList);

.NET 컬렉션을 비교하기 위한 강력한 도구가 부족합니다.아래 링크에서 찾을 수 있는 간단한 솔루션을 개발했습니다.

http://robertbouillon.com/2010/04/29/comparing-collections-in-net/

그러면 순서에 관계없이 동등 비교가 수행됩니다.

var list1 = new[] { "Bill", "Bob", "Sally" };
var list2 = new[] { "Bob", "Bill", "Sally" };
bool isequal = list1.Compare(list2).IsSame;

그러면 항목이 추가/제거되었는지 확인합니다.

var list1 = new[] { "Billy", "Bob" };
var list2 = new[] { "Bob", "Sally" };
var diff = list1.Compare(list2);
var onlyinlist1 = diff.Removed; //Billy
var onlyinlist2 = diff.Added;   //Sally
var inbothlists = diff.Equal;   //Bob

그러면 사전의 어떤 항목이 변경되었는지 확인할 수 있습니다.

var original = new Dictionary<int, string>() { { 1, "a" }, { 2, "b" } };
var changed = new Dictionary<int, string>() { { 1, "aaa" }, { 2, "b" } };
var diff = original.Compare(changed, (x, y) => x.Value == y.Value, (x, y) => x.Value == y.Value);
foreach (var item in diff.Different)
  Console.Write("{0} changed to {1}", item.Key.Value, item.Value.Value);
//Will output: a changed to aaa

저는 Enumerable.SequenceEqual 메서드(매일 뭔가를 배웁니다....)에 대해 몰랐지만 확장 메서드 사용을 제안하려고 했습니다.이 같은:

    public static bool IsEqual(this List<int> InternalList, List<int> ExternalList)
    {
        if (InternalList.Count != ExternalList.Count)
        {
            return false;
        }
        else
        {
            for (int i = 0; i < InternalList.Count; i++)
            {
                if (InternalList[i] != ExternalList[i])
                    return false;
            }
        }

        return true;

    }

흥미롭게도 SequenceEqual에 대해 읽는 데 2초가 걸리면 Microsoft가 내가 설명한 기능을 구축한 것처럼 보입니다.

이것은 귀하의 질문에 직접적으로 대답하지는 않지만 MS의 TestTools와 NUnit은 모두 다음을 제공합니다.

 CollectionAssert.AreEquivalent

당신이 원하는 것을 거의 수행합니다.

컬렉션을 비교하려면 LINQ를 사용할 수도 있습니다. Enumerable.Intersect 동일한 모든 쌍을 반환합니다.다음과 같이 두 개의 사전을 비교할 수 있습니다.

(dict1.Count == dict2.Count) && dict1.Intersect(dict2).Count() == dict1.Count

첫 번째 비교가 필요한 이유는 다음과 같습니다. dict2 모든 키를 포함할 수 있습니다. dict1 그리고 더.

다음을 사용하여 변형을 생각할 수도 있습니다. Enumerable.Except 그리고 Enumerable.Union 비슷한 결과를 가져오는 거죠.그러나 세트 간의 정확한 차이를 결정하는 데 사용할 수 있습니다.

이 예는 어떻습니까?

 static void Main()
{
    // Create a dictionary and add several elements to it.
    var dict = new Dictionary<string, int>();
    dict.Add("cat", 2);
    dict.Add("dog", 3);
    dict.Add("x", 4);

    // Create another dictionary.
    var dict2 = new Dictionary<string, int>();
    dict2.Add("cat", 2);
    dict2.Add("dog", 3);
    dict2.Add("x", 4);

    // Test for equality.
    bool equal = false;
    if (dict.Count == dict2.Count) // Require equal count.
    {
        equal = true;
        foreach (var pair in dict)
        {
            int value;
            if (dict2.TryGetValue(pair.Key, out value))
            {
                // Require value be equal.
                if (value != pair.Value)
                {
                    equal = false;
                    break;
                }
            }
            else
            {
                // Require key be present.
                equal = false;
                break;
            }
        }
    }
    Console.WriteLine(equal);
}

예의: https://www.dotnetperls.com/dictionary-equals

순서가 지정된 컬렉션(목록, 배열)의 경우 사용 SequenceEqual

HashSet 사용을 위해 SetEquals

사전의 경우 다음을 수행할 수 있습니다.

namespace System.Collections.Generic {
  public static class ExtensionMethods {
    public static bool DictionaryEquals<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> d1, IReadOnlyDictionary<TKey, TValue> d2) {
      if (object.ReferenceEquals(d1, d2)) return true; 
      if (d2 is null || d1.Count != d2.Count) return false;
      foreach (var (d1key, d1value) in d1) {
        if (!d2.TryGetValue(d1key, out TValue d2value)) return false;
        if (!d1value.Equals(d2value)) return false;
      }
      return true;
    }
  }
}

(보다 최적화된 솔루션은 정렬을 사용하지만 이를 위해서는 IComparable<TValue>)

아니요.컬렉션 프레임워크에는 평등 개념이 없습니다.생각해보면 주관적이지 않은 컬렉션을 비교할 수 있는 방법은 없습니다.예를 들어 IList를 사전과 비교하면 모든 키가 IList에 있거나 모든 값이 IList에 있거나 둘 다 IList에 있으면 동일할까요?이 두 컬렉션이 무엇에 사용되는지 알지 못하면 이 두 컬렉션을 비교할 수 있는 명확한 방법이 없으므로 일반적인 목적과 같음 방법은 의미가 없습니다.

아니요, 프레임워크는 목록의 내용을 비교하는 방법을 모르기 때문입니다.

이것을 살펴보십시오:

http://blogs.msdn.com/abhinaba/archive/2005/10/11/479537.aspx

public bool CompareStringLists(List<string> list1, List<string> list2)
{
    if (list1.Count != list2.Count) return false;

    foreach(string item in list1)
    {
        if (!list2.Contains(item)) return false;
    }

    return true;
}

그런 일도 없었고, 없을 수도 있습니다. 적어도 저는 그렇게 믿습니다.그 이유는 컬렉션 평등이 아마도 사용자 정의 동작 때문일 것입니다.

컬렉션의 요소는 자연스럽게 순서가 있지만 특정 순서로 되어 있어서는 안 되며 비교 알고리즘이 이에 의존해야 하는 것이 아닙니다.다음과 같은 두 가지 컬렉션이 있다고 가정해 보겠습니다.

{1, 2, 3, 4}
{4, 3, 2, 1}

그들은 평등합니까, 아닌가?당신은 알아야하지만 당신의 관점이 무엇인지 모르겠습니다.

알고리즘이 정렬 규칙을 제공할 때까지 컬렉션은 기본적으로 개념적으로 순서가 지정되지 않습니다.SQL Server가 주의를 끄는 것과 동일한 점은 페이지 매김을 시도할 때 정렬 규칙을 제공해야 한다는 것입니다.

https://docs.microsoft.com/en-US/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-2017

또 다른 두 컬렉션:

{1, 2, 3, 4}
{1, 1, 1, 2, 2, 3, 4}

다시 말하지만, 그들은 동등합니까, 아닌가?당신은 나에게 ..

컬렉션의 요소 반복성은 다양한 시나리오와 다음과 같은 일부 컬렉션에서 역할을 합니다. Dictionary<TKey, TValue> 반복되는 요소도 허용하지 마세요.

나는 이러한 종류의 평등이 애플리케이션 정의이므로 프레임워크가 가능한 모든 구현을 제공하지 않는다고 믿습니다.

뭐, 일반적인 경우에는 Enumerable.SequenceEqual 충분하지만 다음 경우에는 false를 반환합니다.

var a = new Dictionary<String, int> { { "2", 2 }, { "1", 1 }, };
var b = new Dictionary<String, int> { { "1", 1 }, { "2", 2 }, };
Debug.Print("{0}", a.SequenceEqual(b)); // false

나는 이와 같은 질문에 대한 답변을 읽었습니다(아마도 Google 그들을 위해) 그리고 내가 일반적으로 사용할 것은:

public static class CollectionExtensions {
    public static bool Represents<T>(this IEnumerable<T> first, IEnumerable<T> second) {
        if(object.ReferenceEquals(first, second)) {
            return true;
        }

        if(first is IOrderedEnumerable<T> && second is IOrderedEnumerable<T>) {
            return Enumerable.SequenceEqual(first, second);
        }

        if(first is ICollection<T> && second is ICollection<T>) {
            if(first.Count()!=second.Count()) {
                return false;
            }
        }

        first=first.OrderBy(x => x.GetHashCode());
        second=second.OrderBy(x => x.GetHashCode());
        return CollectionExtensions.Represents(first, second);
    }
}

이는 한 컬렉션이 원래 순서를 고려하지 않고 반복되는 시간을 포함하여 요소에서 다른 컬렉션을 나타냄을 의미합니다.구현에 대한 몇 가지 참고 사항:

  • GetHashCode() 평등을 위한 것이 아니라 질서를 위한 것입니다.이 경우에는 충분하다고 생각합니다

  • Count() 실제로 컬렉션을 열거하지 않으며 속성 구현에 직접적으로 속합니다. ICollection<T>.Count

  • 레퍼런스가 같으면 그냥 보리스임

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top