【问题标题】:Comparing Arrays using LINQ in C#在 C# 中使用 LINQ 比较数组
【发布时间】:2010-05-26 13:19:39
【问题描述】:

我有两个类似的数组

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

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

只有当两个数组的大小相同时才应该进行比较。数据可以是任意顺序,如果 a[] 的所有值和 b[] 的所有值都相同,则仍然返回 true。

【问题讨论】:

  • from x in a from y in b where x == y select x == y 但它不正确...不能存储在布尔变量中
  • 每个数组都有唯一的值吗?当您认为两个数组相同时?如果它们具有相同的元素?相同顺序的相同元素?
  • 如果两者完全相同,您是在寻找一个布尔型答案,还是在寻找检查每个元素是否与其伙伴相同。
  • 顺序不同...但两个数组的大小应该相同
  • 这些相等吗? { "a", "a", "b" } , { "a", "b", "b" } 这些相等吗? { "a", "b", "a" } , { "a", "a", "b" }

标签: c# linq


【解决方案1】:
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 毫秒

【讨论】:

  • 但我认为性能不行。路口操作不便宜
  • @Andrey - 这也取决于列表的大小。
  • 在语法上,我会说return (a.Length == b.Length && a.Intersect(b).Count() == a.Length),但这只是我。
  • @Kyle Rozendo:但是等等,这符合 OP 的要求吗?它没有明确说明,但我假设 OP 正在寻找一种方法来检查给定数组是否具有相同的元素以相同的顺序。检查a.Intersect(b).Count() 只会确保它们具有相同的元素,而不检查顺序。
  • 但是,对于存在重复元素(在两个数组中)的情况,此方法不会失败。作为集合操作的相交操作可能只保留不同的元素。因此,如果将其与 Array.length 进行比较,则比较可能会失败。
【解决方案2】:

不确定性能,但这似乎可行。

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

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

但是,它不是独立于订单的,因此不满足 OP 的要求。

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

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

【讨论】:

  • 你是什么意思,“它与订单无关”? SequenceEqual 不是顺序无关的。在您的第二个代码示例中,它将返回 false
  • 不反对,但这并不能回答问题。根据操作:not in same order... but two arrays should have equal size
【解决方案3】:

我认为这将始终是一个 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);
    

    一些用例:

    • 不同的长度(预期为假)

      string[] a = { "a", "b", "c" };
      string[] b = { "b", "c" };
      
    • 不同的顺序(期望为真)

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

    如果输入可以包含重复项,也可以使用,尽管从问题中不清楚是否需要该特征,请考虑:

    • 重复项的计数相同(应为真)

      string[] a = { "a", "b", "b", "c" };
      string[] b = { "a", "b", "c", "b" };
      
    • 具有不同计数的重复项目(预期为假)

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

    【讨论】:

    • 如果你先比较它们的大小,你需要同时包含所有操作吗?
    • @Scott,是的。考虑 a = { "a", "b", "c" }; b = {“c”,“a”。 “一种” };长度相同,但 b 中的唯一项是 a 中的项的子集
    【解决方案5】:

    这适用于重复并检查每个元素

    a.Length == b.Length && !a.Where((t, i) => t != b[i]).Any()
    

    【讨论】:

      【解决方案6】:
      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)));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-02-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-25
        相关资源
        最近更新 更多