Jaka jest przeciwna metoda Any <T>

80

Jak mogę sprawdzić w Linq, czy kolekcja nie zawiera obiektu. IE Przeciwieństwo Any<T>.

Mógłbym odwrócić wynik za pomocą a, !ale ze względu na czytelność zastanawiałem się, czy istnieje lepszy sposób na zrobienie tego? Czy powinienem sam dodać rozszerzenie?

Caspar Kleijne
źródło
Bardziej czytelne !? Contains, Exists?
Tigran,
3
Tak, nie ma None<T>. Często używam takich niestandardowych rozszerzeń dla czytelności (na przykład nie lubię !dictionary.ContainsKey(key)składni, więc dictionary.NoKey(key)zamiast tego zaimplementowałem .
Konrad Morawski
2
@Morawski: Zacząłem używać ConcurrentDictionary, ponieważ jest to bardzo przydatna GetOrAddmetoda, nawet jeśli nie potrzebuję współbieżności.
Roger Lipscombe,

Odpowiedzi:

87

Możesz łatwo utworzyć Nonemetodę rozszerzenia:

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
źródło
1
Czuję, że byłby to miły dodatek do standardowego Linqa.
Ivan
3
@Ivan, nie ma go w samym Linq, ale jest częścią mojej biblioteki Linq.Extras
Thomas Levesque
60

Przeciwieństwem sprawdzenia, czy jakikolwiek (przynajmniej jeden) rekord spełnia określone kryteria, byłoby sprawdzenie, czy wszystkie rekordy nie spełniają kryteriów.

Nie opublikowałeś pełnego przykładu, ale jeśli chciałeś czegoś takiego jak przeciwieństwo:

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

Możesz użyć:

var isJohnNotFound = MyRecords.All(x => x.FirstName != "John");
Grant Winney
źródło
Właśnie trafiłem na to dzisiaj w Google i chociaż zgadzam się z twoim podejściem, zazwyczaj używamvar isJohnNotFound = !MyRecords.All(x => x.FirstName == "John");
Chris
Oczywiście wygłupiałem. Kiedy to robię, nie dzieje się tak, gdy sprawdzam jedno pole. Zwykle jest to bardziej podobne do !MyRecords.All(x => InvalidNames.Any(n => n == x.Name));Więc sprawdź każdy wpis na liście nieprawidłowych nazw, tylko jeśli żadna nie pasuje, wynik będzie prawdziwy.
Chris,
2

Oprócz dodanych odpowiedzi, jeśli nie chcesz zawijać Any()metody, możesz zaimplementować None()w następujący sposób:

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

Oprócz tego w przypadku przeciążenia bez parametrów można zastosować ICollection<T>optymalizację, która w rzeczywistości nie istnieje w implementacji LINQ.

ICollection<TSource> collection = source as ICollection<TSource>;
if (collection != null) { return collection.Count == 0; }
Saro Taşciyan
źródło
2

Znalazłem ten wątek, gdy chciałem dowiedzieć się, czy kolekcja nie zawiera jednego obiektu, ale nie chcę sprawdzać, czy wszystkie obiekty w kolekcji spełniają podane kryteria. Skończyło się na tym, że zrobiłem taki czek:

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

if (!exists)
{
    continue;
}
Ogglas
źródło