C#LINQ方法确定数组是否是另一个的子集(包括重复项)?

时间:2015-03-31 02:03:48

标签: arrays linq

考虑两个数组:

int[] a1 = new int[] { 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10 };
int[] a2 = new int[] { 1, 3, 4, 7, 5, 10, 1 };

我希望能够确定a2是否是a1的子集,考虑重复项目的数量。

换句话说,如果a1有三个“1”,而a2有四个“1”,则a2不是a1的子集。但是,如果a1包含三个“1”,那么只要a2中有三个或更少的“1”,它就应该被认为是一个子集。

使用LINQ的“Intersect”语句的方法不起作用,因为在两个包含三个“1”的数组上进行Intersect会返回一个只有一个“1”的数组。无论阵列中有多少“1”,它都会这样做;它只是想查看两个数组中是否存在该项目。

示例(基于上面的数组a1):

int[] a2 = new int[] { 1, 3, 4, 7, 5, 10, 1 };   // True
int[] a3 = new int[] { 1 };                      // True
int[] a4 = new int[] { 9, 3, 5, 1, 1, 10, 10 };  // True
int[] a5 = new int[] { 1, 1, 1, 1, 10, 10 };     // False
int[] a6 = new int[] { 1, 2, 3, 3, 4, 5 };       // False
int[] a7 = new int[] { 10, 10, 10 };             // False
int[] a8 = new int[0];                           // False

有没有办法使用LINQ完成所需的结果?

通过将所有数组转换为列表,迭代和从列表中删除项目,我认为这是一种相当丑陋的方法。如果有一个更优雅的解决方案,我只是好奇。

3 个答案:

答案 0 :(得分:1)

class Program
    {
        static void Main(string[] args)
        {
            int[] a1 = new int[] { 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10 };
            int[] a2 = new int[] { 1, 3, 4, 7, 5, 10, 1 };
            int[] a3 = new int[] { 1 };                      // True
            int[] a4 = new int[] { 9, 3, 5, 1, 1, 10, 10 };  // True
            int[] a5 = new int[] { 1, 1, 1, 1, 10, 10 };     // False
            int[] a6 = new int[] { 1, 2, 3, 3, 4, 5 };       // False
            int[] a7 = new int[] { 10, 10, 10 };             // False
            int[] a8 = new int[0];

            Console.WriteLine(a2.IsSubSetOf(a1));
            Console.WriteLine(a3.IsSubSetOf(a1));
            Console.WriteLine(a4.IsSubSetOf(a1));
            Console.WriteLine(a5.IsSubSetOf(a1));
            Console.WriteLine(a6.IsSubSetOf(a1));
            Console.WriteLine(a7.IsSubSetOf(a1));
            Console.WriteLine(a8.IsSubSetOf(a1));
            Console.ReadLine();
        }
    }

    public static class Ext
    {
        public static bool IsSubSetOf(this IEnumerable<int> other, IEnumerable<int> a1)
        {
            var a1Group = a1.GroupBy(i => i).Select(g => new { Num = g.Key, Count = g.Count() }).ToList();
            var otherGroup = other.GroupBy(i => i).Select(g => new { Num = g.Key, Count = g.Count() }).ToList();

            return other != null
                   && other.Any()
                   && otherGroup.Count <= a1Group.Count
                   && otherGroup.All(o => a1Group.Single(a => a.Num == o.Num).Count >= o.Count);
        }
    }

答案 1 :(得分:0)

这一切都在一行中。可读性值得怀疑。还需要一个附加子句来处理空数组。

bool isSubset = ints.GroupBy(i => i).All(g => a1.Count(i => i == g.Key) >= g.Count()) && ints.Count() > 0;

答案 2 :(得分:0)

这对我来说非常直接:

var l1 = a1.ToLookup(x => x);
var l2 = a2.ToLookup(x => x);

var check = l2.All(xs => xs.Count() <= l1[xs.Key].Count());

这适用于所有示例数据,除了空集 - 我认为应该将其视为子集,因此我认为这应该适用于所有这些数据。

相关问题