【问题标题】:C# Comparing two lists of lists of objectsC#比较两个对象列表列表
【发布时间】:2014-02-20 20:26:59
【问题描述】:

我不知道我在哪里犯了错误,但我无法比较(例如)整数列表的两个列表。

简单示例:

List<List<int>> A = new List<List<int>>();
A.Add(new List<int>(new int[] { 1 }));
A.Add(new List<int>(new int[] { 2 }));

List<List<int>> B = new List<List<int>>();
B.Add(new List<int>(new int[] { 1 }));

if (A.Contains(B[0])){
    Console.WriteLine("TRUE");
else{
    Console.WriteLine("FALSE");
}

返回 False。在这种情况下比较的正确方法是什么?我也尝试了IntersectExcept,结果相同。

【问题讨论】:

  • 你想用A.Contains(B[0])实现什么?您是否希望它告诉您 A 中的任何列表是否与提供的列表具有完全相同的内容?相同顺序的相同元素?顺序重要吗?如果 B 中的列表是 A 中的列表的子集怎么办?这是真的还是假的?
  • 它是假的,因为它不是同一个列表引用(它直接比较列表,而不仅仅是其中的元素)。
  • 外面的List&lt;&gt;在这里不相关,你的核心问题是比较2List&lt;int&gt;{1, 2} 等于 {2, 1} 吗?
  • 在我的例子中,“相等”的意思是“相同顺序的相同元素”。

标签: c# list compare


【解决方案1】:

这可能有助于形象化:

A:
   A[0]:
       A[0][0]: 1
   A[1]:
       A[1][0]: 2
B:
   B[0]:
       B[0][0]: 1

当您调用A.Contains() 时,您是在询问您正在测试的对象是A[0] 还是A[1]。由于您将它传递给B,而B 不是这两者,它返回false。即使你将它传递给B[0]B[0][0],你仍然会得到错误,因为它们都不是与A[0]A[1] 相同的对象。

SequenceEqual()是检测两个List的内容是否相同的函数。所以你想测试A[0]A[1]是否是SequenceEqualB[0](即A[0][0] == B[0][0]A[1][0] == B[0][0])。

最好的方法是使用 LINQ 函数.Any()A.Any(a =&gt; a.SequenceEqual(B[0])) 将针对 A 中的所有内容测试 B[0]。如果您想将 all B 元素与 all A 元素进行比较,则需要类似于 A.Any(a =&gt; B.Any(b =&gt; a.SequenceEqual(b)) 的东西。这可以翻译为:

foreach (var a in A) // A[0], A[1], etc.
{ 
    foreach (var b in B) // B[0], B[1], etc.
    {
       // is our current a value matching the current b value?
       // i.e. A[0] is exactly the same as B[0] on the first pass
       if (a.SequenceEqual(b)) return true; 
    }
}
return false;

【讨论】:

  • 我怀疑,这个问题是由某种引用相等引起的,但我不知道如何解决它。感谢您的解释。
【解决方案2】:

您可以遍历 A 中的每个列表并将其与 B[0] 与 SequenceEqual 进行比较:

if (A.Any(list => list.SequenceEqual(B[0])))
{
    Console.WriteLine("TRUE");
}
else
{
     Console.WriteLine("FALSE");
}

将返回 true

【讨论】:

    【解决方案3】:
    bool contains = A.Any(a => B.Any(b => b.OrderBy(x => x)
                                           .SequenceEqual(a.OrderBy(x => x))));
    

     [[1],[2]]    and [[3]]       => false
     [[1],[2]]    and [[1]]       => true
     [[2],[1]]    and [[1],[2]]   => true
     [[3],[4]]    and [[1],[2]]   => false
     [[1,2],[3]]  and [[2,1],[4]] => true
    

    【讨论】:

    • @Jonesy 问题不清楚。我假设[2,1] 等于[1,2]。否则 SequenceEqual 将返回 false。
    【解决方案4】:

    对于字符串以外的引用类型,如果运算符 == 的两个操作数引用同一个对象,则返回 true。这显然不是您将一个列表引用与另一个列表引用进行比较的情况。

    【讨论】:

    • 如果string 作为通用参数传递,它实际上(令人惊讶?)做同样的事情。
    • @Grozz - == 应用于List&lt;&gt;s,而不是Ts
    • @HenkHolterman 我明白了。我只是说,如果你有通用的Some&lt;T&gt; 并将其参数与== 进行比较,它将对T &lt;- List&lt;int&gt;T &lt;- string 使用引用相等性
    【解决方案5】:

    您正在比较列表,默认情况下会比较引用是否相等。 对于这种特殊情况,您可以通过以下方式使用SequenceEqual 扩展:

    bool contains = A.Any(a => a.SequenceEqual(B[0]));
    Console.WriteLine(contains);  
    

    这可能对您的目的足够有效,也可能不够有效:)

    解决此问题的另一种方法是在 SequenceEqual 周围编写自己的 IEqualityComparer 包装器,如下所述:IEqualityComparer for SequenceEqual 然后将其用作.Contains 调用中的参数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多