使用 LINQ 在 C# 中比较数组

25

我有两个数组,例如:

string[] a = { "a", "b", "c" };
string[] b = { "a", "b", "c" };

我需要使用LINQ比较这两个数组。

当且仅当两个数组具有相同的大小时,才应进行比较。如果a []和b []的所有值都相同,则可以任意排列数据并仍然返回true。


从a中选取x,在b中选取y,其中x等于y,然后选择x等于y。但这是不正确的...无法存储在布尔变量中。 - Thorin Oakenshield
每个数组是否具有唯一的值? 当您认为两个数组相同时,它们是否具有相同的元素?是具有相同顺序的相同元素吗? - Itay Karo
那么将{“a”,“b”,“c”}与{“b”,“a”,“c”}进行比较,返回true? - Scott Chamberlain
7
这两组数据是否相等?{ "a", "a", "b" },{ "a", "b", "b" } 这两组数据是否相等?{ "a", "b", "a" },{ "a", "a", "b" } - Itay Karo
@Itay:它们不能相等,因为它们都有不同的项目(数量上)。这些项目不需要按照相同的顺序排列,但应该恰好有一个项目。例如,{"a","a","b"}和{"a","b","a"}是相等的。 - Thorin Oakenshield
显示剩余3条评论
6个回答

34
string[] a = { "a", "b" };
string[] b = { "a", "b" };

return (a.Length == b.Length && a.Intersect(b).Count() == a.Length);

进行了一些性能测试:

  • 10,000个小字符串 - 5毫秒
  • 100,000个小字符串 - 99毫秒
  • 1,000,000个小字符串 - 平均601毫秒
  • 100,000个 ~500字符的字符串 - 190毫秒

1
但我认为性能不够好。交集操作并不便宜。 - Andrey
4
从语法上讲,我会说 return (a.Length == b.Length && a.Intersect(b).Count() == a.Length),但这只是我的看法。 - ZombieSheep
1
@Kyle Rozendo:等等,这是否符合原帖的要求?虽然没有明确说明,但我会认为原帖作者正在寻找一种方法来检查给定的数组是否具有相同顺序的相同元素。检查a.Intersect(b).Count()只能确保它们具有相同的元素,而不检查顺序。 - Dan Tao
3
但是,如果存在重复元素(在两个数组中均有),这种方法是否会失败?由于交集操作是一种集合操作,可能仅保留不同的元素。因此,如果将其与Array.length进行比较,则比较可能会失败。 - josephj1989
即使第二个数组的顺序改变,此代码将返回true,例如string[] b = {"b", "a"};。 - Sahi
显示剩余4条评论

27

不确定性能如何,但这似乎有效。

string[] a = { "a", "b", "c" };
string[] b = { "a", "b", "c" };

bool result = a.SequenceEqual(b);
Assert.AreEqual(true, result);

然而,它不是无序的,因此它不符合原始问题的要求。

string[] a = { "a", "b", "c" };
string[] b = { "a", "c", "b" };

bool result = a.SequenceEqual(b);
Assert.AreEqual(false, result);

3
“it is order independent”是什么意思?SequenceEqual不是独立于顺序的。在你的第二个代码示例中,它将返回false。 - Thomas Levesque
不是要点踩,但这并没有回答问题。根据楼主的要求:“不按相同顺序...但两个数组应该具有相等的大小”。 - Kyle Rosendo

5

我认为这将始终是O(n log n)的操作,所以我会将两个数组排序并进行比较,例如使用SequenceEqual。


4

如果顺序无关或者允许重复,那么也许可以这样:

public static class IEnumerableExtensions
{
    public static bool HasSameContentsAs<T>(this ICollection<T> source,
                                            ICollection<T> other)
    {
        if (source.Count != other.Count)
        {
            return false;
        }
        var s = source
            .GroupBy(x => x)
            .ToDictionary(x => x.Key, x => x.Count());
        var o = other
            .GroupBy(x => x)
            .ToDictionary(x => x.Key, x => x.Count());
        int count;
        return s.Count == o.Count &&
               s.All(x => o.TryGetValue(x.Key, out count) &&
                          count == x.Value);
    }
}

用法:

string[] a = { "a", "b", "c" };
string[] b = { "c", "a", "b" };

bool containSame = a.HasSameContentsAs(b);

一些使用案例:

  • different lengths (expect false)

    string[] a = { "a", "b", "c" };
    string[] b = { "b", "c" };
    
  • different order (expect true)

    string[] a = { "a", "b", "c" };
    string[] b = { "b", "c", "a" };
    

如果输入可以包含重复项,则也适用,尽管从问题中无法确定是否需要该特性,请考虑以下内容:

  • duplicated items have same count (expect true)

    string[] a = { "a", "b", "b", "c" };
    string[] b = { "a", "b", "c", "b" };
    
  • duplicated items with different counts (expect false)

    string[] a = { "a", "b", "b", "b", "c" };
    string[] b = { "a", "b", "c", "b", "c" };
    

如果你先比较它们的大小,那么你是否需要执行两个containsAll操作呢? - Scott Chamberlain
1
@Scott,是的。考虑a = {"a", "b", "c"}; b = {"c", "a". "a"}; 长度相同,但b中唯一的项是a中的子集。 - Handcraftsman

4
这可以正确处理重复项并检查每个元素。
a.Length == b.Length && !a.Where((t, i) => t != b[i]).Any()

3
IDictionary<int, object> a = new Dictionary<int, object>();
IDictionary<int, object> b = new Dictionary<int, object>();
a.Add(1, "1");
a.Add(2, 2);
a.Add(3, "3");

b.Add(3, "3");
b.Add(1, "1");
b.Add(2, 2);

Console.WriteLine(a.All(i => b.Contains(i)) && b.All(i => a.Contains(i)));

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