# C# LINQ方法来确定数组是否是另一个数组的子集（包括重复的）？[英] C# LINQ method to determine if array is subset of another (including duplicates)?

### 问题描述

```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[] 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
```

## 推荐答案

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

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

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