获得;“差别”;在C#中的两个数组之间?

获得;“差别”;在C#中的两个数组之间?,c#,arrays,C#,Arrays,假设我有两个数组: var array1 = new[] {"A", "B", "C"}; var array2 = new[] {"A", "C", "D"}; 我想知道两者之间的区别。我知道我可以用几行代码来编写,但我想确保我没有丢失内置语言特性或LINQ扩展方法 理想情况下,我会得到以下三个结果: 项目不在第1列,但在第2列(“D”) 项目不在第2列,但在第1列(“B”) 这两个文件中都包含的项目 提前谢谢 如果您有LINQ可用,您可以使用和。您在问题中要求的集合分别是: - arr

假设我有两个数组:

var array1 = new[] {"A", "B", "C"};
var array2 = new[] {"A", "C", "D"};
我想知道两者之间的区别。我知道我可以用几行代码来编写,但我想确保我没有丢失内置语言特性或LINQ扩展方法

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

  • 项目不在第1列,但在第2列(“D”)
  • 项目不在第2列,但在第1列(“B”)
  • 这两个文件中都包含的项目

提前谢谢

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

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

public void Linq52(){
int[]numbersA={0,2,4,5,6,8,9};
int[]numbersB={1,3,5,7,8};
IEnumerable aOnlyNumbers=numbersA.Except(numbersB);
WriteLine(“第一个数组中的数字,而不是第二个数组:”);
foreach(aOnlyNumbers中的变量n){
控制台写入线(n);
}
}

我不得不用非常大的数据集做类似的事情。如果你要处理几千个左右的问题,请使用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++]);
}
intia=0;
int-iB=0;
List inA=新列表();
List inB=新列表();
List INBOOT=新列表();
while(iA

同样,只有在处理数十万个值的情况下,才需要这样做。

以下是LINQ扩展方法的基准。结果是在实际程序的开发过程中获得的

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

我测试了Except扩展方法

var except=lst2.except(lst1)

List lst=except.ToList()

这两行产生了600项“新添加项”列表。我用秒表对象计时。速度惊人:220ms。我用的电脑决不是“快速的冈萨雷斯”。核心2 Duo T7700–2.4GHz

注:

这是实现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;
    }
}
公共类密钥:IEquatable
{
公共int索引{get;private set;}
公共字符串名称{get;private set;}
公钥(字符串keyName,int-sdIndex)
{
this.Name=keyName;
this.Index=sdIndex;
}
//合理实施
公共布尔等于(关键其他)
{
//检查比较对象是否为空。
if(Object.ReferenceEquals(other,null))返回false;
//检查比较对象是否引用相同的数据。
if(Object.ReferenceEquals(this,other))返回true;
//检查产品的属性是否相等。
返回Index.Equals(other.Index)和&Name.Equals(other.Name);
}
//对于一对对象,If Equals()返回true
//然后GetHashCode()必须为这些对象返回相同的值。
公共覆盖int GetHashCode()
{
//如果名称字段不为null,则获取其哈希代码。
int hashKeyName=Name==null?0:Name.GetHashCode();
//获取索引字段的哈希代码。
int hashKeyIndex=Index.GetHashCode();
//计算密钥的哈希代码。
返回hashKeyName^hashKeyIndex;
}
}

另一种解决方案如下所示

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));

你知道这是什么样的性能保证吗?可能需要先为每个数组创建一个排序副本。我在MSDN上找不到任何内容。不,它没有排序副本。它从排除序列创建一个集合,然后在源序列上迭代,生成任何不在排除序列中的元素。(当我说“set”时,我指的是“hash set”。)谢谢,我希望这可以在我的应用程序中使用,但由于我的数据是预排序的,而且非常大,速度损失太高。
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));