Проверьте, содержит ли один набор значений другой
Предположим, что у меня есть две коллекции:
Collection1:
"A1"
"A1"
"M1"
"М2"
Collection2:
"M2"
"M3"
"M1"
"A1"
"A1"
"А2"
все значения являются строковыми значениями. Я хочу знать, содержатся ли все элементы Collection1 в Collection2, но у меня нет гарантии на порядок, и набор может иметь несколько записей с одинаковым значением. В этом случае Collection2 содержит Collection1, потому что Collection2 имеет два A1, M1 и M2. Theres очевидным образом: сортировка обеих коллекций и выскакивание значений, когда я нахожу совпадения, но мне было интересно, есть ли более эффективный способ сделать это. Снова с исходными коллекциями у меня нет гарантии по порядку или сколько раз будет отображаться данное значение
EDIT: Изменен набор для коллекции, чтобы очистить, что они не являются наборами, поскольку они могут содержать повторяющиеся значения
Ответы
Ответ 1
Да, есть более быстрый способ, если вы не ограничены по пространству. (См. коммюнике пространства/времени.)
Алгоритм:
Просто вставьте все элементы в Set2 в хеш-таблицу (в С# 3.5, что HashSet <string> ), а затем пройдете все элементы Set1 и проверьте, находятся ли они в хеш-таблице. Этот метод выполняется быстрее (Θ (m + n)), но использует O (n) пространство.
В качестве альтернативы просто скажите:
bool isSuperset = new HashSet<string>(set2).IsSupersetOf(set1);
Изменить 1:
Для тех людей, которые обеспокоены возможностью дублирования (и, следовательно, неправильного "набора" ), идея может быть легко расширена:
Просто создайте новый Dictionary<string, int>
, представляющий количество каждого слова в супер-списке (добавьте его в счетчик каждый раз, когда вы увидите экземпляр существующего слова, и добавьте слово со счетом 1, если оно не в словаре), а затем перейдите в список и уменьшите счетчик каждый раз. Если каждое слово существует в словаре, и счетчик никогда не равен нулю, когда вы пытаетесь уменьшить его, то подмножество на самом деле является под-списком; в противном случае у вас было слишком много экземпляров слова (или его вообще не было), поэтому он не является реальным под-списком.
Изменить 2:
Если строки очень большие, и вы обеспокоены эффективностью пространства, и для вас работает алгоритм, который работает с (очень) высокой вероятностью, а затем попытайтесь сохранить хэш каждой строки. Технически он не гарантированно работает, но вероятность того, что он не работает, довольно низок.
Ответ 2
Самый сжатый способ, которым я знаю:
//determine if Set2 contains all of the elements in Set1
bool containsAll = Set1.All(s => Set2.Contains(s));
Ответ 3
Проблема, которую я вижу с ответами HashSet, Intersect и другими Set, заключается в том, что вы имеете дубликаты, а "Набор - это коллекция, которая не содержит повторяющихся элементов". Здесь можно обрабатывать повторяющиеся случаи.
var list1 = new List<string> { "A1", "A1", "M1", "M2" };
var list2 = new List<string> { "M2", "M3", "M1", "A1", "A1", "A2" };
// Remove returns true if it was able to remove it, and it won't be there to be matched again if there a duplicate in list1
bool areAllPresent = list1.All(i => list2.Remove(i));
EDIT: я переименовал из Set1 и Set2 в list1 и list2, чтобы успокоить Mehrdad.
РЕДАКТИРОВАТЬ 2: комментарий подразумевает это, но я хотел явно указать, что это изменяет list2. Делайте это так, только если вы используете его в качестве сравнения или контроля, но впоследствии не нуждаетесь в содержимом.
Ответ 4
Отъезд linq...
string[] set1 = {"A1", "A1", "M1", "M2" };
string[] set2 = { "M2", "M3", "M1", "A1", "A1", "A2" };
var matching = set1.Intersect(set2);
foreach (string x in matching)
{
Console.WriteLine(x);
}
Ответ 5
Аналогичный
string[] set1 = new string[] { "a1","a2","a3","a4","a5","aa","ab" };
string[] set2 = new string[] {"m1","m2","a4","a6","a1" };
var a = set1.Select(set => set2.Contains(set));