Я пишу запрос в Linq, который должен проверить, проходят ли один или несколько элементов в списке предикат A(), а нет - предикат {{X1} }. Чтобы включить Linq to SQL, нужен один запрос. Итак, для следующих списков результаты должны быть такими, где a передает предикат A(), а b передает предикат B():

1. [ a, a ] => true
2. [ a ]    => true
3. [ a, b ] => false
4. [ b, b ] => false
5. [ b ]    => false
6. [ ]      => false

Я пробовал следующее, но у каждого из них есть определенные ситуации, когда они не работают:

// Fails in case 6
MyList.All(x => A(x) && !B(x));

// Fails in case 3
MyList.Where(x => !B(x)).Count(x => A(x)) > 0;

// This works, but it's not a single query anymore
MyList.All(x => A(x) && !B(x)) && Mylist.Count() > 0;

Я чувствую, что мне здесь нужно что-то эквивалентное всем, но которое возвращает false для пустого списка. Например, это будет проходить во всех случаях:

MyList.AllButReturnFalseIfListIsEmpty(x => A(x) && !B(x));

Как я могу этого добиться?

3
Alfie Woodland 6 Сен 2016 в 12:00

5 ответов

Лучший ответ

Я бы предложил вам что-то похожее на мой ответ на Linq All в пустой коллекции :

var result = MyList.Max(x => B(x) ? (int?)2 : A(X) ? (int?)1 : (int?)0) == 1;

Он использует принцип работы метода Max<int?>

(A) Если последовательность пуста, она возвращает null
(B) Если существует хотя бы один элемент, соответствующий B, результат будет 2
(C) Если есть хотя бы один элемент, не соответствующий B и соответствующий A, результат будет 1
(D) В противном случае результат будет 0

Итак, мы просто проверим случай (C).

1
Community 23 Май 2017 в 11:51

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

MyList.All(x => MyList.Any() && A(x) && !B(x));
0
toadflakz 6 Сен 2016 в 09:10

Вы не должны использовать All (), если хотите, чтобы он возвращал false для пустой коллекции. Взгляните на документация:

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

Вместо этого я бы попробовал что-то вроде этого:

MyList.Where(x => A(x) && !B(x)).Any();
0
J. Swietek 6 Сен 2016 в 09:17

Почему бы вам просто не проверить, есть ли какой-нибудь предмет после оценки?

MyList.Where(x => A(x) && !B(x)).Any();
0
Mauro Sampietro 6 Сен 2016 в 09:17

Сделать это можно так:

var result = MyList
    .Select(x => B(x) ? -1 : (A(x) ? 1 : 0))
    .Aggregate(0, (p, v) => v == -1 || p == -1 ? -1 : p + v) > 0;

Запрос работает следующим образом:

  • Select производит -1, когда B равно true; в противном случае он производит 1, если A равно true, и 0, если A ложно
  • Aggregate проверяет этот список номеров из -1, 0, 1. Если он видит -1, результатом агрегирования будет -1. В противном случае результатом агрегации является сумма положительных значений.
  • Сравнение в конце гарантирует, что есть хотя бы один A и нет B s.
2
Sergey Kalinichenko 6 Сен 2016 в 09:14