Проверьте, является ли массив подмножеством другого

StackOverflow https://stackoverflow.com/questions/332973

  •  22-07-2019
  •  | 
  •  

Вопрос

Есть идеи, как проверить, является ли этот список подмножеством другого?

Конкретно у меня есть

List<double> t1 = new List<double> { 1, 3, 5 };
List<double> t2 = new List<double> { 1, 5 };

Как проверить, что t2 является подмножеством t1, используя LINQ?

Это было полезно?

Решение

bool isSubset = !t2.Except(t1).Any();

Другие советы

Используйте HashSet вместо List, если работаете с наборами. Тогда вы можете просто использовать IsSubsetOf ()

HashSet<double> t1 = new HashSet<double>{1,3,5};
HashSet<double> t2 = new HashSet<double>{1,5};

bool isSubset = t2.IsSubsetOf(t1);

Извините, что он не использует LINQ. : - (

Если вам нужно использовать списки, то решение @ Jared работает с предупреждением о том, что вам нужно будет удалить все повторяющиеся элементы, которые существуют.

Если вы юнит-тестирование , вы также можете использовать CollectionAssert.IsSubsetOf метод:

CollectionAssert.IsSubsetOf(subset, superset);

В приведенном выше случае это будет означать:

CollectionAssert.IsSubsetOf(t2, t1);

Решение @Cameron как метод расширения:

public static bool IsSubsetOf<T>(this IEnumerable<T> a, IEnumerable<T> b)
{
    return !a.Except(b).Any();
}

Использование:

bool isSubset = t2.IsSubsetOf(t1);

(Это похоже, но не совсем то же самое, что опубликовано в блоге @Michael)

Это значительно более эффективное решение, чем другие, размещенные здесь, особенно топовое решение:

bool isSubset = t2.All(elem => t1.Contains(elem));

Если вы можете найти один элемент в t2, которого нет в t1, то вы знаете, что t2 не является подмножеством t1. Преимущество этого метода в том, что он выполняется на месте, без выделения дополнительного пространства, в отличие от решений, использующих .Except или .Intersect. Кроме того, это решение может сломаться, как только оно найдет один элемент, который нарушает условие подмножества, в то время как другие продолжают поиск. Ниже приведена оптимальная длинная форма решения, которая в моих тестах лишь незначительно быстрее, чем приведенное выше сокращенное решение.

bool isSubset = true;
foreach (var element in t2) {
    if (!t1.Contains(element)) {
        isSubset = false;
        break;
    }
}

Я провел некоторый элементарный анализ производительности всех решений, и результаты оказались радикальными. Эти два решения примерно в 100 раз быстрее, чем решения .Except () и .Intersect (), и не используют дополнительную память.

Опираясь на ответы @Cameron и @Neil, я написал метод расширения, использующий ту же терминологию, что и класс Enumerable.

/// <summary>
/// Determines whether a sequence contains the specified elements by using the default equality comparer.
/// </summary>
/// <typeparam name="TSource">The type of the elements of source.</typeparam>
/// <param name="source">A sequence in which to locate the values.</param>
/// <param name="values">The values to locate in the sequence.</param>
/// <returns>true if the source sequence contains elements that have the specified values; otherwise, false.</returns>
public static bool ContainsAll<TSource>(this IEnumerable<TSource> source, IEnumerable<TSource> values)
{
    return !values.Except(source).Any();
}

Здесь мы проверяем, присутствует ли какой-либо элемент в дочернем списке (т.е. t2), который не содержится в родительском списке (т.е. t1).Если такого списка не существует, то этот список является подмножеством другого

например:

bool isSubset = !(t2.Any(x => !t1.Contains(x)));

Попробуйте это

static bool IsSubSet<A>(A[] set, A[] toCheck) {
  return set.Length == (toCheck.Intersect(set)).Count();
}

Идея в том, что Intersect будет возвращать только те значения, которые есть в обоих массивах. На этом этапе, если длина результирующего набора совпадает с исходным набором, тогда все элементы в " множестве " также находятся в разделе "проверить" и, следовательно, «набор» является подмножеством «toCheck»

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

Подсказка: я голосовал за ответ Кэмерон.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top