Qual è l'uso di. Any () in un elenco C #?

34

Ne ho discusso con i colleghi e non siamo riusciti a capire quale sia l'utilizzo di .Any per ogni dato List<> , in C #.

Puoi verificare la validità di un elemento nella matrice come la seguente dichiarazione:

if (MyList.Any()){ ...}  //Returns true or false

Che è esattamente uguale a

if (MyList.Count() != 0) { ... }

ed è molto più comune, leggibile e chiaro sull'intento dell'istruzione if .

Alla fine, eravamo bloccati da questo pensiero:

.Any() can be used, will work just as well, but is less clear about the intent of the programmer, and it that case it should not be used.

Ma riteniamo che questo non possa essere giusto; dobbiamo perdere qualcosa.

Siamo?

    
posta Gil Sand 04.09.2015 - 20:16
fonte

5 risposte

88

Ricorda che Any non funziona su List ; funziona su IEnumerable , che rappresenta un tipo concreto che può avere o meno una proprietà Count . È vero che non è necessariamente la cosa migliore da usare su List , ma è sicuramente utile alla fine di una query LINQ. E ancora più utile della versione standalone è l'override che prende un predicato proprio come Where . Non c'è nulla di integrato in List che sia quasi conveniente o espressivo come il metodo di estensione predicato- Any .

Inoltre, se stai utilizzando Count() (il metodo di estensione LINQ per IEnumerable), anziché Count (la proprietà su List ), può essere necessario enumerare l'intera sequenza se non è possibile ottimizzare questa funzione rilevando il tipo di dati sottostante ha una proprietà Count . Se hai una lunga sequenza, questo può essere un notevole risultato in termini di prestazioni quando non ti interessa veramente quale sia il conteggio, e vuoi solo sapere se ci sono elementi nella collezione.

    
risposta data 04.09.2015 - 20:21
fonte
52

C'è una differenza del tempo di esecuzione Count() può essere O (n) dove Any() è O (1).

    
risposta data 04.09.2015 - 20:26
fonte
9

In realtà, tieni presente che esiste List.Count proprietà, e poi c'è Enumerable.Count metodo.

Nel tuo esempio, stai utilizzando il metodo Enumerable.Count() , che deve scorrere ogni singolo elemento dell'enumerazione per restituire un risultato. Questo è chiaramente più lento di chiamare Any() che deve solo scorrere il primo elemento, se esiste.

Modifica

Nei commenti è stato sottolineato, giustamente, che il metodo di estensione Enumerable.Count() non ha bisogno di scorrere tutti gli elementi se rileva che anche l'enumerabile è un ICollection<T> . Quindi, nel caso di un List<T> , l'utilizzo della proprietà Count o del metodo in realtà non fa differenza.

IEnumerable.Count fonte:

public static int Count<TSource>(this IEnumerable<TSource> source) {
    if (source == null) throw Error.ArgumentNull("source");
    ICollection<TSource> collectionoft = source as ICollection<TSource>;
    if (collectionoft != null) return collectionoft.Count;
    ICollection collection = source as ICollection;
    if (collection != null) return collection.Count;
    int count = 0;
    using (IEnumerator<TSource> e = source.GetEnumerator()) {
        checked {
            while (e.MoveNext()) count++;
        }
    }
    return count;
}
    
risposta data 04.09.2015 - 20:28
fonte
5

Una domanda sorprendente: trovo che l'intento di list.Any() sia molto più chiaro dell'intento di list.Count()!=0 .

Intenti significa: se leggi il codice di qualcuno (e non lo hai scritto tu stesso), è del tutto ovvio ciò che il programmatore vuole raggiungere e perché ha scritto scritto così com'è? Se un problema comune viene risolto in un modo inutilmente complesso, vieni immediatamente sospettoso e ti chiedi perché lo sviluppatore non abbia usato il modo semplice. Guardi attraverso il codice e provi a vedere se hai perso qualcosa. Hai paura di cambiare il codice perché ti preoccupi che ci sono alcuni effetti collaterali che ti mancano e cambiarlo potrebbe causare problemi imprevisti.

L'intenzione di utilizzare il metodo Any() è completamente chiara: vuoi sapere se ci sono elementi nella lista o meno.

L'intento dell'espressione Count()!=0 d'altra parte non è ovvio per il lettore. Ovviamente non è difficile vedere che l'espressione ti dice se l'elenco è vuoto o no. Le domande sorgono perché la scrivi in questo modo particolare piuttosto che utilizzare il metodo standard. Perché usi Count() esplicitamente? Se hai davvero bisogno di sapere se ci sono elementi in un elenco, perché vuoi prima contare l'intero elenco? Appena raggiungi 1 hai già la tua risposta. Se la sorgente era un iteratore su una grande (forse infinita) collezione o è stata tradotta in sql, potrebbe fare una grande differenza in termini di prestazioni. Quindi forse l'uso esplicito di Count () è di forzare una query differita da eseguire o attraversare un iteratore?

Ma la fonte è in realtà un List<T> dove Count() è O (1) e non ha effetti collaterali. Ma se il codice si basa su questa proprietà di List<T> , allora perché non usare la Count -property che indica più chiaramente che ti aspetti un'operazione O (1) senza effetti collaterali?

Come è scritto, list.Count()!=0 fa esattamente lo stesso di list.Any() eccetto che è inutilmente più complesso e l'intento non è chiaro.

    
risposta data 05.09.2015 - 17:07
fonte
2

Forse è solo la parola? Any è un aggettivo, in realtà non dice nulla. Venendo da Java, lo chiamerei isNonEmpty che contiene un verbo. Un utente di SQL potrebbe preferire EXISTS . Ma forse Any si adatta meglio al sistema C #.

Qualunque sia la scelta delle parole, una volta che ci si abitua, deve essere più chiaro. Chiederesti "C'è ancora una percentuale di bottiglie di birra in meno". Ti aspetteresti che more than zero persone inizino a contarli prima che rispondano "No, non c'è one or more "?

    
risposta data 05.09.2015 - 01:14
fonte

Leggi altre domande sui tag