【问题标题】:What's the fastest way to compare two arrays for equality?比较两个数组是否相等的最快方法是什么?
【发布时间】:2011-05-08 09:02:00
【问题描述】:

我有两个对象数组,它们可能具有相同的值,但顺序不同,例如

{ "cat", "dog", "mouse", "pangolin" }

{ "dog", "pangolin", "cat", "mouse" }

我希望将这两个数组视为平等。最快的测试方法是什么?

【问题讨论】:

    标签: c# arrays algorithm equality


    【解决方案1】:

    我不能保证这是最快的,但它肯定非常高效:

    bool areEquivalent = array1.Length == array2.Length 
                         && new HashSet<string>(array1).SetEquals(array2);
    

    编辑: SaeedAlg 和 Sandris 提出了关于导致这种方法出现问题的不同重复频率的有效点。如果这很重要,我可以看到两种解决方法(没有过多考虑它们各自的效率):

    1.对数组进行排序,然后依次比较。理论上,这种方法在最坏的情况下应该具有二次复杂度。 例如:

    return array1.Length == array2.Length
           && array1.OrderBy(s => s).SequenceEqual(array2.OrderBy(s => s));
    

    2.在每个数组中建立一个字符串频率表,然后比较它们。例如:

    if(array1.Length != array2.Length)
       return false;
    
    var f1 = array1.GroupBy(s => s)
                   .Select(group => new {group.Key, Count = group.Count() });
    
    var f2 = array2.GroupBy(s => s)
                   .Select(group => new {group.Key, Count = group.Count() });
    
    return !f1.Except(f2).Any();
    

    【讨论】:

    • 这就像@Albin Sunnanbo 的回答可能是你返回两个数组相等但它们不相等。
    • @SaeedAlg:你能举个例子吗?
    • @Ani:一个例子是 {"cat", "cat", "dog"}, {"cat", "dog", "dog"}。这些数组不是彼此的排列,但您的表达式返回 true。
    • @SaeedAlg,@sandris:谢谢。关于我建议的解决方法的任何 cmets?
    • @Andikki:是的,但是 SequenceEqual 在 OrderBy 之后,所以在很多情况下快速失败检查可以帮助不必要的排序。
    【解决方案2】:

    我会使用 HashSet,假设没有重复项

    string[] arr1 = new string[] { "cat", "dog", "mouse", "pangolin" };
    string[] arr2 = new string[] { "dog", "pangolin", "cat", "mouse" };
    
    bool result = true;
    if (arr1.Length != arr2.Length)
    {
        result = false;
    }
    else
    {
        HashSet<string> hash1 = new HashSet<string>(arr1);
        foreach (var s in arr2)
        {
            if (!hash1.Contains(s))
                result = false;
        }
    }
    

    编辑:
    如果您只有四个元素,则跳过 HashSet 并在比较中使用 arr1.Contains 可能会更快。根据您的阵列大小测量并选择最快的。

    【讨论】:

    • 有正误报,hash不支持不为不同的item做唯一值
    • 这在理论上更便宜,但实际上只说 hash1 = HashSet(arr1); 可能会更快。 hash2 = HashSet(arr2); hash1.SetEquals(hash2)
    【解决方案3】:

    我认为唯一合理的方法是对它们进行排序然后进行比较。

    排序需要O(n logn)和比较O(n),所以还是O(n logn)的总数

    【讨论】:

    • 当然,这假设您可以在恒定时间内比较两个单词。如果单词可以变得更长,尽管它们也有助于运行时。
    • 比较两个字符串就像比较 GetHashCode() 一样简单
    【解决方案4】:

    将两个数组都转换为 HashSet 并使用 setequals

    【讨论】:

      【解决方案5】:

      你有没有尝试过类似的东西

      string[] arr1 = {"cat", "dog", "mouse", "pangolin"};
      
      string[] arr2 = {"dog", "pangolin", "cat", "mouse"};
      
      bool equal = arr1.Except(arr2).Count() == 0 && arr2.Except(arr1).Count() == 0;
      

      【讨论】:

        【解决方案6】:

        伪代码:

        A:array
        B:array
        C:hashtable
        
        if A.length != B.length then return false;
        
        foreach objA in A
        {
        H = objA;
        if H is not found in C.Keys then
        C.add(H as key,1 as initial value);
        else
        C.Val[H as key]++;
        }
        
        foreach objB in B
        {
        H = objB;
        if H is not found in C.Keys then
        return false;
        else
        C.Val[H as key]--;
        }
        
        if(C contains non-zero value)
        return false;
        else
        return true;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-07-26
          • 2018-05-21
          • 1970-01-01
          • 1970-01-01
          • 2010-09-22
          • 2023-03-29
          • 1970-01-01
          相关资源
          最近更新 更多