C#: 如何检查两个列表的元素数量和内容是否相同?

6

这里有两个字符串列表

List<string> A;
List<string> B;

您会建议编写多短的代码来检查 A.Count == B.Count 以及 A 中的每个元素是否在 B 中, 反之亦然:即 A 和 B 中的每个元素都相等(A 和 B 的顺序可能不同)。

6个回答

25

如果您不必担心重复:

bool equal = new HashSet<string>(A).SetEquals(B);

如果你关心重复问题,那会变得稍微麻烦一些。以下代码可以解决,但速度相对较慢:

bool equal = A.OrderBy(x => x).SequenceEquals(B.OrderBy(x => x));

当然,您可以通过首先检查计数来使这两个选项更有效率,这是一个简单的表达式。例如:

bool equal = (A.Count == B.Count) && new HashSet<string>(A).SetEquals(B);

...但你要求最短的代码 :)


2
A.Count == B.Count && new HashSet<string>(A).SetEquals(B);

如果重复项的不同频率是一个问题,请查看这个问题

1
如果你在这两个列表上调用 Enumerable.Except(),它将返回一个 IEnumerable<string>,其中包含所有存在于一个列表中但不存在于另一个列表中的元素。如果其计数为0,则说明这两个列表相同。

1
Enumerable.Distinct() 操作的是 一个 序列。您是否意思是 Enumerable.Except() - Jon Skeet
@Jon 是的,我明白了,谢谢你的澄清。我会更新我的答案。 - Andy

0

如果你不关心重复,或者你关心重复但并不过分关心性能微观优化,那么Jon答案中的各种技术绝对是正确的选择。

如果你既关心重复关心性能,那么像这样的扩展方法应该能解决问题,虽然它确实不符合你的“最短代码”标准!

bool hasSameElements = A.HasSameElements(B);

// ...

public static bool HasSameElements<T>(this IList<T> a, IList<T> b)
{
    if (a == b) return true;

    if ((a == null) || (b == null)) return false;

    if (a.Count != b.Count) return false;

    var dict = new Dictionary<string, int>(a.Count);
    foreach (string s in a)
    {
        int count;
        dict.TryGetValue(s, out count);
        dict[s] = count + 1;
    }

    foreach (string s in b)
    {
        int count;
        dict.TryGetValue(s, out count);

        if (count < 1) return false;

        dict[s] = count - 1;
    }

    return dict.All(kvp => kvp.Value == 0);
}

(请注意,如果两个序列都为null,则此方法将返回true。 如果这不是所需的行为,则很容易添加额外的null检查。)


0
var result = A.Count == B.Count && A.Where(y => B.Contains(y)).Count() == A.Count;

可能吗?


谢谢,我也写了类似的代码,但是@Jon Skeet提供了更加优秀的代码 :) - Andrew Florko

0

一个简单的循环怎么样?

private bool IsEqualLists(List<string> A, List<string> B)
{
    for(int i = 0; i < A.Count; i++)
    {
        if(i < B.Count - 1) {
            return false; }
        else 
        {
            if(!String.Equals(A[i], B[i]) {
                return false;
            }
        }
    }
    return true;
}

我更喜欢像下面答案中的基于Groovy Linq的方式。A.SequenceEqual非常棒。 - Tom
这假设两个列表的顺序是相同的 - 它们可能不是,即使它们是,那么SequenceEqual也正如你所说的,更加优雅。 - LukeH
啊,是的,我实际上误读了问题,事实上不同的顺序是可以接受的。好的,非 Linq 路线应该是 A.TrueForAll(a => B.Contains(a));。 - Tom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接