2015-03-31 2 views
1

Рассмотрим два массива:Метод C# 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» в нем, его следует считать подмножеством.

Методы, использующие инструкцию LINKS 'Intersect', не работают, как и Intersect на двух массивах, каждая из которых содержит три «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?

Я рассмотрел довольно уродливый способ сделать это, преобразовывая все массивы в списки, итерации и удаления элементов из списков. Мне было просто любопытно, есть ли более элегантное решение.

ответ

0

Это довольно прямо вперед для меня:

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

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

Это работает со всеми вами, например, данные, за исключением пустого набора - который я думаю, что следует рассматривать как подмножество, так что я думаю, что это должно отлично работают для всех.

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

Это получает все в одной строке. Читаемость сомнительна. Также ему понадобилось дополнительное предложение для обработки пустого массива.

bool isSubset = ints.GroupBy(i => i).All(g => a1.Count(i => i == g.Key) >= g.Count()) && ints.Count() > 0; 
Смежные вопросы