【问题标题】:Comparing two List<string> for equality比较两个 List<string> 是否相等
【发布时间】:2010-12-05 12:55:25
【问题描述】:

除了逐个遍历元素之外,我如何比较两个字符串列表是否相等(在 .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 );

【问题讨论】:

标签: c# .net collections comparison equality


【解决方案1】:

试试下面的

var equal = expected.SequenceEqual(actual);

测试版

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

SequenceEqual 扩展方法将比较集合中的元素以确保相等。

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

【讨论】:

  • 感谢您的回答。那只是.NET 3.5吗?我忘了提到我使用的是 .NET 3.0。
  • @Adam,是的。 SequenceEquals 是 3.5 中定义的扩展方法,尽管它很容易移植到 2.0 项目中。
  • 它不会详细说明为什么集合不同,而 CollectionAssert.AreEqual() 会。
  • SequenceEqual 不是 SequenceEquals msdn.microsoft.com/en-us/library/bb348567(v=vs.100).aspx
  • 您需要添加using System.Linq ;才能使用如图所示的方法。
【解决方案2】:

许多测试框架都提供 CollectionAssert 类:

CollectionAssert.AreEqual(expected, actual);

例如MS Test

【讨论】:

  • 唉,它在失败时给出的消息有点没用,例如。 “不同数量的元素”或“索引 0 处的元素不匹配”,而不告诉您 它们是什么
【解决方案3】:

你总是可以自己编写需要的函数:

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

【讨论】:

  • 不错!我希望避免单步执行这些元素,但这是您编写方法的一种很好的通用方式。
  • 赞成,这是一个很好的答案。但是,请注意,如果任一列表为空,该函数将引发异常。建议在函数开头添加以下语句:if (list1 == null &amp;&amp; list2 == null) return true;if (list1 == null || list2 == null) return false;
【解决方案4】:

我注意到没有人真正告诉您为什么您的原始代码不起作用。这是因为== 运算符在一般测试reference equality(即,如果两个实例指向内存中的同一个对象),除非运算符是overloadedList&lt;T&gt; 未定义 == 运算符,因此使用基引用等于实现。

正如其他海报所展示的那样,您通常必须逐步检查元素来测试“集合相等性”。当然,您应该使用用户DreamWalker 建议的优化,在单步执行之前先测试集合的计数。

【讨论】:

  • 谢谢!我自己可以想出几种方法来进行比较,但是当我遇到这个问题时,我想“好吧,它显然不是在检查相等性,那它在做什么呢?”
【解决方案5】:

你可以这样写一个扩展方法:

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

【讨论】:

  • @Adam:我意识到您使用的是 .NET 3.0 而不是 .NET 3.5 我将编辑我的答案,通过使其成为静态方法而不是扩展来使代码可用于 .NET 3.0方法
【解决方案6】:

虽然它确实迭代了集合,但我创建的这个扩展方法不需要两个列表的顺序相同,并且它也适用于复杂类型,只要重写 Equals 方法即可。

以下两个列表将返回 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();
}

【讨论】:

    【解决方案7】:

    使用 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();
    }
    

    【讨论】:

      【解决方案8】:

      如果顺序很重要:

      bool equal = a.SequenceEquals(b);
      

      如果顺序无关紧要:

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

      【讨论】:

        【解决方案9】:

        它可能以非常规方式使用,但没有实现自定义类型的 IEquatable

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

        但在一般情况下,您可以使用 cmets https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.sequenceequal?view=netframework-4.8 中提到的 SequenceEqual

        另外不要忘记为自定义类型实现 IEquatable 接口(字符串类型或其他结构不需要)

        【讨论】:

          猜你喜欢
          • 2013-08-18
          • 2021-09-14
          • 2023-03-11
          • 2016-03-06
          • 1970-01-01
          • 2015-11-15
          • 2014-12-03
          • 2014-09-20
          相关资源
          最近更新 更多