【问题标题】:Getting the "diff" between two arrays in C#?在 C# 中获取两个数组之间的“差异”?
【发布时间】:2009-03-25 20:28:19
【问题描述】:

假设我有这两个数组:

var array1 = new[] {"A", "B", "C"};
var array2 = new[] {"A", "C", "D"};

我想了解两者之间的差异。我知道我可以用几行代码来编写它,但我想确保我没有遗漏内置语言功能或 LINQ 扩展方法。

理想情况下,我最终会得到以下三个结果:

  • 不在array1 中但在array2 ("D") 中的项目
  • 项目不在 array2 中,但在 array1 ("B") 中
  • 两者中的项目

提前致谢!

【问题讨论】:

    标签: c# arrays


    【解决方案1】:

    如果您有可用的 LINQ,则可以使用 ExceptDistinct。您在问题中要求的集合分别是:

    - array2.Except(array1)
    - array1.Except(array2)
    - array1.Intersect(array2)
    

    【讨论】:

    • 你知道这是一种什么样的履约保证吗?据推测,除了必须首先制作每个数组的排序副本。我在 MSDN 上找不到这些。
    • 不,它不会生成排序副本。它从排除序列创建一个集合,然后遍历源序列,产生任何不在排除序列中的元素。
    • (当我说“set”时,我的意思是“hash set”。)
    • 谢谢,我希望这将是我可以在我的应用程序中使用的东西,但是由于我的数据是预先排序的并且非常大,所以速度损失太高了。
    【解决方案2】:

    来自MSDN 101 LINQ samples....

    public void Linq52() {
        int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
        int[] numbersB = { 1, 3, 5, 7, 8 };
    
        IEnumerable<int> aOnlyNumbers = numbersA.Except(numbersB);
    
        Console.WriteLine("Numbers in first array but not second array:");
        foreach (var n in aOnlyNumbers) {
            Console.WriteLine(n);
        }
    }
    

    【讨论】:

      【解决方案3】:

      这里是 LINQ 扩展方法的基准。结果是在实际程序的开发过程中得到的。

      测试: 2 个列表(lst1 和 lst2),每个列表大约 250000 个对象。每个对象(Key 类)都包含一个字符串和一个整数。第二个列表主要包含与第一个相同的条目,但添加了一些新条目,删除了一些。

      我测试了 except 扩展方法。

      var except = lst2.Except(lst1);

      列表 lst = except.ToList();

      这 2 行产生了 600 个“新增”项目列表。我使用 StopWatch 对象对其进行计时。速度惊人:220 ms。我使用的计算机绝不是“快速冈萨雷斯”。酷睿 2 双核 T7700 – 2.4GHz。

      注意:

      这里是Key类,它实现了IEquatable i-face。

      public class Key : IEquatable<Key>
      {
          public int Index { get; private set; }
          public string Name { get; private set; }
      
          public Key(string keyName, int sdIndex)
          {
              this.Name = keyName;
              this.Index = sdIndex;
          }
      
       // IEquatable implementation
          public bool Equals(Key other)
          {
              //Check whether the compared object is null.
              if (Object.ReferenceEquals(other, null)) return false;
              //Check whether the compared object references the same data.
              if (Object.ReferenceEquals(this, other)) return true;
              //Check whether the products' properties are equal.
              return Index.Equals(other.Index) && Name.Equals(other.Name);
          }
      
          // If Equals() returns true for a pair of objects 
          // then GetHashCode() must return the same value for these objects.
          public override int GetHashCode()
          {
              //Get hash code for the name field if it is not null.
              int hashKeyName = Name == null ? 0 : Name.GetHashCode();
              //Get hash code for the index field.
              int hashKeyIndex = Index.GetHashCode();
              //Calculate the hash code for the Key.
              return hashKeyName ^ hashKeyIndex;
          }
      }
      

      【讨论】:

        【解决方案4】:

        我不得不用非常大的数据集做类似的事情。如果您要处理几千个左右,请使用 Linq 的东西,因为它更清晰。但是,如果您知道您的数组是预先排序的,那么运行这样的合并可以显着加快速度,因为它只需要一次通过数据,并且不需要像 Linq 版本那样分配尽可能多的内存。

        int iA = 0;
        int iB = 0;
        List<int> inA = new List<int>();
        List<int> inB = new List<int>();
        List<int> inBoth = new List<int>();
        while (iA < numbersA.Length && iB < numbersB.Length)
        {
            if (numbersA[iA] < numbersB[iB])
            {
                inA.Add(numbersA[iA++]);
            }
            else if (numbersA[iA] == numbersB[iB])
            {
                inBoth.Add(numbersA[iA++]);
                ++iB;
            }
            else
            {
                inB.Add(numbersB[iB++]);
            }
        }
        while (iA < numbersA.Length)
        {
            inA.Add(numbersA[iA++]);
        }
        while (iB < numbersB.Length)
        {
            inB.Add(numbersB[iB++]);
        }
        

        同样,只有在处理数十万个值时才需要这样做。

        【讨论】:

          【解决方案5】:

          另一种解决方案也如下所示

          int[] arr1 = new int[] { 45, 26, 99, 55, 36 };
          int[] arr2 = new int[] { 45, 26, 99, 20, 36 };
          
          var res = arr1.Union(arr2).Except(arr1.Intersect(arr2));
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-06-15
            • 2010-11-14
            相关资源
            最近更新 更多