linq 两个列表的交集〈int[]>

wyyhbhjk  于 2023-03-10  发布在  其他
关注(0)|答案(2)|浏览(135)

我想得到下面两个列表的交集。

List<int[]> list1 = new List<int[]>
{
    new int[] { 0, 0, 0, },
    new int[] { 1, 1, 1, }
};

List<int[]> list2 = new List<int[]>
{
    new int[] { 1, 1, 1, },
    new int[] { 2, 2, 2, }
};

但当我尝试

List<int[]> intersection = list1.Intersect(list2).ToList();

交集返回空。当我用两个List<int>(不是数组)尝试这个精确的设置时,它按预期工作。
这是我第一次使用Linq.我怎样才能到达这个十字路口?

8oomwypt

8oomwypt1#

使用Where()Any()的方法
您可以比较列表/数组以及继承IEnumerable的每个对象与SequenceEqual的相等性

List<int[]> intersection = list1.Where(l1 => list2.Any(l2=> l1.SequenceEqual(l2))).ToList();
q3aa0525

q3aa05252#

用于检查是否相等的默认比较器是引用比较
此默认值不适合比较数组的内容。
您可以使用自定义比较器(从IEqualityComparer派生)来实现所需的功能,它实际上比较数组的内容:

// Custom comparer:
class MyComparer : IEqualityComparer<int[]>
{
    public bool Equals(int[] a, int[] b) 
    {
        if (ReferenceEquals(a, b)) return true; 
        if (a is null) return false; 
        if (b is null) return false;
        return a.SequenceEqual(b); 
    }
    public int  GetHashCode(int[] a)     
    { 
        return a.Aggregate(1, (acc, item) => acc * item); 
    }
}

然后,您可以将以下内容用于交点:

List<int[]> list1 = new List<int[]>
            {
                new int[] { 0, 0, 0, },
                new int[] { 1, 1, 1, }
            };

List<int[]> list2 = new List<int[]>
            {
                new int[] { 1, 1, 1, },
                new int[] { 2, 2, 2, }
            };

// Intersection with custom comparer:
//------------------------------------------------vvvvvvvvvvvvvvvv----------
List<int[]> intersection = list1.Intersect(list2, new MyComparer()).ToList();

foreach (var list in intersection)
{
    Console.WriteLine("{0}", string.Join(", ", list));
}

输出:

1, 1, 1

注:

我的GetHashCode实现只是一个您可能需要改进的小问题。
你可以在下面看到@奥利弗关于如何改进它的评论(它需要Microsoft.Bcl.HashCode NuGet for HashCode)。
我的GetHashCode的另一个问题是它需要遍历整个数组。当数组很长时,它也会溢出。正如@Dmitry Bychenko所评论的,你可以使用下面的代码来代替(还需要来自Microsoft.Bcl.HashCode的HashCode):

return HashCode.Combine(a.DefaultIfEmpty().Take(4));

这将最多考虑4个项目,并让.Net将它们组合起来。

相关问题