Я пытаюсь найти пересечение с 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 в этом случае.. Я не знаю заранее, если списки заполняются...
Если вам это нужно за один шаг, самое простое решение - отфильтровать пустые списки:
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));
}
Затем вы можете использовать его на коллекции списков или других IEnumerable
s:
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);
Вы можете написать метод расширения для определить это поведение. Что-то вроде
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);
}