问题描述
考虑两个数组:
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的"交叉"语句的方法不起作用,因为在两个包含三个"1"的数组上的相交,只需单个"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α→
实现所需的结果我已经考虑了通过将所有数组转换为列表,迭代和从列表中删除项目来执行相当丑陋的方式.如果有更优雅的解决方案,我只是好奇.
推荐答案
这非常直接向我:
var l1 = a1.ToLookup(x => x); var l2 = a2.ToLookup(x => x); var check = l2.All(xs => xs.Count() <= l1[xs.Key].Count());
这与您所有示例数据一起使用,除了空集 - 我认为应该被视为一个子集,所以我认为这应该适用于所有这些.
其他推荐答案
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); } }
其他推荐答案
这可以在一行中获取.可读性是值得怀疑的.还需要一个额外的子句来处理空数组.
bool isSubset = ints.GroupBy(i => i).All(g => a1.Count(i => i == g.Key) >= g.Count()) && ints.Count() > 0;
问题描述
Consider two arrays:
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 };
I want to be able to determine if a2 is a subset of a1, considering the number of duplicate items.
In other words, if a1 has three "1"'s, and a2 has four "1"'s, then a2 is not a subset of a1. However, if a1 contains three "1"'s, then as long as a2 has three or less "1"'s in it, it should be considered a subset.
Methods using LINQ's "Intersect" statement don't work, as doing Intersect on two arrays each containing three "1"'s returns an array with just a single "1". It will do this regardless of how many "1"'s are in either array; it's only looking to see if the item exists in both arrays.
Examples (based on array a1 above):
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
Is there a way to accomplish the desired result using LINQ?
I've considered a rather ugly way of doing this by converting all the arrays into lists, iterating, and removing items from the lists. I was just curious if there is a more elegant solution.
推荐答案
This is quite straight forward to me:
var l1 = a1.ToLookup(x => x); var l2 = a2.ToLookup(x => x); var check = l2.All(xs => xs.Count() <= l1[xs.Key].Count());
This works with all of you example data, except the empty set - which I think should be considered a subset, so I think this should work fine for all of them.
其他推荐答案
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); } }
其他推荐答案
This gets it all in one line. Readability is questionable. Also it needed an additional clause to handle the empty array.
bool isSubset = ints.GroupBy(i => i).All(g => a1.Count(i => i == g.Key) >= g.Count()) && ints.Count() > 0;