Каков метод, противоположный Any <T>

80

Как я могу проверить с Linq, если коллекция не содержит объекта. IE Противоположность Any<T>.

Я мог бы инвертировать результат с помощью, !но для удобства чтения я задавался вопросом, есть ли более лучший способ сделать это? Стоит ли самому добавлять расширение?

Каспар Клейне
источник
Тогда более читабельно !? Contains, Exists?
Тигран
3
Да нет None<T>. Я часто использую такие специальные расширения для удобства чтения (например, мне не нравится !dictionary.ContainsKey(key)синтаксис, поэтому я реализовал его dictionary.NoKey(key)вместо него.
Конрад Моравски,
2
@Morawski: Я начал использовать ConcurrentDictionary, потому что это действительно удобный GetOrAddметод, даже когда мне не нужен параллелизм.
Роджер Липскомб

Ответы:

87

Вы можете легко создать Noneметод расширения:

public static bool None<TSource>(this IEnumerable<TSource> source)
{
    return !source.Any();
}

public static bool None<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    return !source.Any(predicate);
}
Томас Левеск
источник
1
Я считаю, что это было бы хорошим дополнением к стандартному Linq.
Иван
3
@Ivan, этого нет в самом Linq, но это часть моей библиотеки Linq.Extras
Томас Левеск
60

Противоположность проверке того, что любая (хотя бы одна) запись соответствует определенным критериям, будет проверять, что все записи не соответствуют критериям.

Вы не разместили свой полный пример, но если вам нужно что-то противоположное, например:

var isJohnFound = MyRecords.Any(x => x.FirstName == "John");

Вы можете использовать:

var isJohnNotFound = MyRecords.All(x => x.FirstName != "John");
Грант Винни
источник
Только что наткнулся на это сегодня в Google, и, хотя я согласен с вашим подходом, я обычно используюvar isJohnNotFound = !MyRecords.All(x => x.FirstName == "John");
Крис
Конечно, я пошутил. Когда я это делаю, не проверяется ни одно поле. Обычно это больше похоже на " !MyRecords.All(x => InvalidNames.Any(n => n == x.Name));Так что проверяйте каждую запись на соответствие списку недопустимых имен, только если ни одно совпадение не соответствует действительности".
Крис
2

В дополнение к добавленным ответам, если вы не хотите обертывать Any()метод, вы можете реализовать None()следующее:

public static bool None<TSource>(this IEnumerable<TSource> source) 
{
    if (source == null) { throw new ArgumentNullException(nameof(source)); }

    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
        return !enumerator.MoveNext();
    }
}

public static bool None<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    if (source == null) { throw new ArgumentNullException(nameof(source)); }
    if (predicate == null) { throw new ArgumentNullException(nameof(predicate)); }

    foreach (TSource item in source)
    {
        if (predicate(item))
        {
            return false;
        }
    }

    return true;
}

В дополнение к этому для перегрузки без параметров вы можете применить ICollection<T>оптимизацию, которая фактически не существует в реализации LINQ.

ICollection<TSource> collection = source as ICollection<TSource>;
if (collection != null) { return collection.Count == 0; }
Саро Ташчян
источник
2

Нашел эту ветку, когда хотел узнать, не содержит ли коллекция одного объекта, но я не хочу проверять, соответствуют ли все объекты в коллекции заданным критериям. В итоге я сделал такую ​​проверку:

var exists = modifiedCustomers.Any(x => x.Key == item.Key);

if (!exists)
{
    continue;
}
Огглас
источник