¿Cuál es el método opuesto de Any <T>

80

¿Cómo puedo consultar con Linq si una colección no contiene un objeto? Es decir, lo contrario de Any<T>.

Podría invertir el resultado con un !pero para mejorar la legibilidad me preguntaba si había una mejor manera de hacer esto ¿Debo agregar la extensión yo mismo?

Caspar Kleijne
fuente
¿Más legible entonces !? Contains, Exists?
Tigran
3
Sí, no hay None<T>. A menudo uso estas extensiones personalizadas para facilitar la lectura (por ejemplo, no me gusta la !dictionary.ContainsKey(key)sintaxis, así que implementé en su dictionary.NoKey(key)lugar.
Konrad Morawski
2
@Morawski: Empecé a usar ConcurrentDictionary, porque es el GetOrAddmétodo realmente útil , incluso cuando no necesito concurrencia.
Roger Lipscombe

Respuestas:

87

Puede crear fácilmente un Nonemétodo de extensión:

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);
}
Thomas Levesque
fuente
1
Siento que esta sería una buena adición al Linq estándar.
Ivan
3
@Ivan, no está en Linq, pero es parte de mi biblioteca Linq.Extras
Thomas Levesque
60

Lo contrario de verificar que cualquier registro (al menos uno) coincida con un criterio determinado sería verificar que todos los registros no coincidan con los criterios.

No publicó su ejemplo completo, pero si quería lo contrario de algo como:

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

Podrías usar:

var isJohnNotFound = MyRecords.All(x => x.FirstName != "John");
Grant Winney
fuente
Me encontré con esto hoy en Google, y aunque estoy de acuerdo con su enfoque, normalmente usovar isJohnNotFound = !MyRecords.All(x => x.FirstName == "John");
Chris
Por supuesto, me equivoqué. Cuando hago esto, no es con un solo campo marcado. Por lo general, es más parecido. !MyRecords.All(x => InvalidNames.Any(n => n == x.Name));Por lo tanto, verifique cada entrada con una lista de nombres no válidos, solo si ninguno coincide, el resultado será verdadero.
Chris
2

Además de las respuestas agregadas, si no desea ajustar el Any()método, puede implementarlo de la None()siguiente manera:

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;
}

Además de eso para la sobrecarga sin parámetros, puede aplicar ICollection<T>optimización, que en realidad no existe en la implementación de LINQ.

ICollection<TSource> collection = source as ICollection<TSource>;
if (collection != null) { return collection.Count == 0; }
Saro Taşciyan
fuente
2

Encontré este hilo cuando quería saber si una colección no contiene un objeto, pero no quiero verificar que todos los objetos de una colección coincidan con los criterios dados. Terminé haciendo una verificación como esta:

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

if (!exists)
{
    continue;
}
Ogglas
fuente