LINQ пересекаются, несколько списков, некоторые пустеют

Я пытаюсь найти пересечение с LINQ.

Образец:

List<int> int1 = new List<int>() { 1,2 };
List<int> int2 = new List<int>();
List<int> int3 = new List<int>() { 1 };
List<int> int4 = new List<int>() { 1, 2 };
List<int> int5 = new List<int>() { 1 };

Хотите возвратиться: 1, поскольку это существует во всех списках.. Если я работаю:

var intResult= int1
            .Intersect(int2)
            .Intersect(int3)
            .Intersect(int4)
            .Intersect(int5).ToList();

Это ничего не возвращает, поскольку 1, очевидно, не находится в списке int2. Как я заставляю это работать независимо, если один список пуст или нет?

Используйте вышеупомянутый пример или:

List<int> int1 = new List<int>() { 1,2 };
List<int> int2 = new List<int>();
List<int> int3 = new List<int>();
List<int> int4 = new List<int>();
List<int> int5 = new List<int>();

Как я возвращаюсь 1 и 2 в этом случае.. Я не знаю заранее, если списки заполняются...

10
задан Kobi 7 July 2010 в 04:14
поделиться

2 ответа

Если вам это нужно за один шаг, самое простое решение - отфильтровать пустые списки:

public static IEnumerable<T> IntersectNonEmpty<T>(this IEnumerable<IEnumerable<T>> lists)
{
    var nonEmptyLists = lists.Where(l => l.Any());
    return nonEmptyLists.Aggregate((l1, l2) => l1.Intersect(l2));
}

Затем вы можете использовать его на коллекции списков или других IEnumerables:

IEnumerable<int>[] lists = new[] { l1, l2, l3, l4, l5 };
var intersect = lists.IntersectNonEmpty();

Вы можете предпочесть обычный статический метод:

public static IEnumerable<T> IntersectNonEmpty<T>(params IEnumerable<T>[] lists)
{
    return lists.IntersectNonEmpty();
}

var intersect = ListsExtensionMethods.IntersectNonEmpty(l1, l2, l3, l4, l5);
15
ответ дан 3 December 2019 в 21:19
поделиться

Вы можете написать метод расширения для определить это поведение. Что-то вроде

static class MyExtensions
{
    public static IEnumerable<T> IntersectAllIfEmpty<T>(this IEnumerable<T> list, IEnumerable<T> other)
    {
        if (other.Any())
            return list.Intersect(other);
        else
            return list;
    }
}

Таким образом, приведенный ниже код будет печатать 1.

List<int> list1 = new List<int>() { 1, 2 };
List<int> list2 = new List<int>();
List<int> list3 = new List<int>() { 1 };

foreach (int i in list1.IntersectAllIfEmpty(list2).IntersectAllIfEmpty(list3))
    Console.WriteLine(i);

Обновление:

Аноним поднимает хороший момент в комментариях к вопросу. Вышеупомянутая функция будет привести к пустому набору, если сам список пуст, что должно быть желательно. Это означает, что если первый список в цепочке методов или результирующий набор любого пересечения пуст, окончательный результат будет пустым.

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

public static IEnumerable<T> IntersectAllIfEmpty<T>(params IEnumerable<T>[] lists)
{
    IEnumerable<T> results = null;

    lists = lists.Where(l => l.Any()).ToArray();

    if (lists.Length > 0)
    {
        results = lists[0];

        for (int i = 1; i < lists.Length; i++)
            results = results.Intersect(lists[i]);
    }
    else
    {
        results = new T[0];
    }

    return results;
}

Вы бы использовали его так

List<int> list0 = new List<int>();
List<int> list1 = new List<int>() { 1, 2 };
List<int> list2 = new List<int>() { 1 };
List<int> list3 = new List<int>() { 1,2,3 };

foreach (int i in IntersectAllIfEmpty(list0, list1, list2, list3))
{
    Console.WriteLine(i);
}
2
ответ дан 3 December 2019 в 21:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: