0
var subset = new[] { 9, 3, 9 };
var superset = new[] { 9, 10, 5, 3, 3, 3 };
subset.All(s => superset.Contains(s))

This code would return true, because 9 is included in the superset,but only once, I want an implementation that would take into account the duplicates, so it would return false

IOEnthusiast
  • 105
  • 6
  • Off the top of my head, you could group bothsets by count, then test that the super group list contained every key from the sub group list and, in each case, the super count was greater than or equal to the corresponding subcount. I'll see if I can implement that for an answer. – John Sep 25 '22 at 10:22

4 Answers4

2

My thought was that you could group both sets by count, then test that the super group list contained every key from the sub group list and, in each case, the super count was greater than or equal to the corresponding subcount. I think that I've achieved that with the following:

var subset = new[] { 9, 3, 9 };
var superset = new[] { 9, 10, 5, 3, 3, 3 };

var subGroups = subset.GroupBy(n => n).ToArray();
var superGroups = superset.GroupBy(n => n).ToArray();

var basicResult = subset.All(n => superset.Contains(n));
var advancedResult = subGroups.All(subg => superGroups.Any(supg => subg.Key == supg.Key && subg.Count() <= supg.Count()));

Console.WriteLine(basicResult);
Console.WriteLine(advancedResult);

I did a few extra tests and it seemed to work but you can test some additional data sets to be sure.

John
  • 3,057
  • 1
  • 4
  • 10
2

Here is another solution :

            var subset = new[] { 9, 3, 9 };
            var superset = new[] { 9, 10, 5, 3, 3, 3 };

            var subsetGroup = subset.GroupBy(x => x).Select(x => new { key = x.Key, count = x.Count() });
            var supersetDict = superset.GroupBy(x => x).ToDictionary(x => x.Key, y => y.Count());

            Boolean results = subsetGroup.All(x => supersetDict[x.key] >= x.count);
jdweng
  • 33,250
  • 2
  • 15
  • 20
  • Won't that throw an exception if the superset doesn't contain a value that the subset does? I was going to add an option using a dictionary to my answer but, as you've already done that, I'll just suggest an improvement that will avoid that exception: `subsetGroup.All(x => supersetDict.TryGetValue(x.key, out var count) && count >= x.count);`. – John Sep 25 '22 at 10:43
  • subsetGroup.All(x => supersetDict.ContainsKey(x) && count >= x.count); – jdweng Sep 25 '22 at 11:08
  • Nope. If you don't want to use `TryGetValue` then `subsetGroup.All(x => supersetDict.ContainsKey(x) && supersetDict[x] >= x.count);`. Your first try didn't check for the key and your second try didn't get the value. `TryGetValue` does both. – John Sep 25 '22 at 11:11
2

This works for me:

var subsetLookup = subset.ToLookup(x => x);
var supersetLookup = superset.ToLookup(x => x);

bool flag =
    subsetLookup
        .All(x => supersetLookup[x.Key].Count() >= subsetLookup[x.Key].Count());
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
1

That's not how sets and set operations work. Sets cannot contain duplicates.

You should treat the two arrays not as sets, but as (unordered) sequences. A possible algorithm would be: make a list from the sequence superset, then remove one by one each element of the sequence subset from the list until you are unable to find such an element in the list.

bool IsSubList(IEnumerable<int> sub, IEnumerable<int> super)
{
    var list = super.ToList();
    foreach (var item in sub)
    {
        if (!list.Remove(item))
            return false; // not found in list, so sub is not a "sub-list" of super
    }
    return true; // all elements of sub were found in super
}

var subset = new[] { 9, 3 };
var superset = new[] { 9, 10, 5, 3,1, 3, 3 };

var isSubSet = IsSubList(subset, superset);
Klaus Gütter
  • 11,151
  • 6
  • 31
  • 36