A che serve .Any () in un elenco C # <>?


40

Ne ho discusso con i colleghi e non siamo riusciti a capire a cosa serva .Anyun dato List<>, in C #.

È possibile verificare la validità di un elemento nell'array come la seguente istruzione:

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

Che è esattamente lo stesso di

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

ed è molto più comune, leggibile e chiaro circa l'intento della ifdichiarazione.

Alla fine, siamo rimasti bloccati da questo pensiero:

.Any() può essere usato, funzionerà altrettanto bene, ma è meno chiaro sull'intento del programmatore, e in tal caso non dovrebbe essere usato.

Ma riteniamo che questo non possa essere giusto; ci manca qualcosa.

Siamo noi?


40
in che modo le intenzioni sono meno chiare?
jk.

35
Sfido la tua affermazione che Any()è meno chiara: mi Any()sembra più chiara, specialmente con una condizione lambda. Traducendo il codice in inglese nella mia testa, if(MyList.Count(o => o > 10) > 0)diventa "Il numero di elementi è maggiore di 10 in più di 0?" mentre if(MyList.Any(o => o > 10))diventa "Ci sono elementi superiori a 10?"
BlueRaja - Danny Pflughoeft il

3
@SargeBorsch - solo se preferisci Heskel / denominazione funzionale, cosa che la maggior parte delle persone non fa.
Assapora Ždralo il

4
@ BlueRaja-DannyPflughoeft sono d'accordo. Penso che uno sia più chiaro poiché elimina un ciò che potrebbe essere considerato un numero magico.
Andy,

2
@SargeBorsch: SQL parallel to Anyis Exists. Il nome Linq è probabilmente più ispirato a Haskell e Python che hanno anche tutte le funzioni.
Jacques B,

Risposte:


95

Tieni presente che Anynon funziona su un List; opera su un IEnumerable, che rappresenta un tipo concreto che può o meno avere una Countproprietà. È vero che non è necessariamente la cosa migliore da usare su un 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 Listciò che sia conveniente o espressivo come il Anymetodo di estensione del predicato .

Inoltre, se si utilizza Count()(il metodo di estensione LINQ per IEnumerable), anziché Count(la proprietà attiva List), potrebbe essere necessario enumerare l'intera sequenza se non è possibile ottimizzarla via rilevando che il tipo di dati sottostante ha una Countproprietà . Se si dispone di una lunga sequenza, questo può essere un successo notevole delle prestazioni quando non si interessa davvero quello che il conteggio è, e vogliono solo sapere se ci sono eventuali elementi della collezione.


19
Questo. Le prestazioni a parte, Any()con un predicato sono più espressive rispetto al confronto dell'override Enumerable.Count()che prende un predicato con 0. :)
Dan J

1
Penso che questo spieghi i fondamenti così chiaramente che spieghi la risposta al meglio.
Tarik,

2
IMHO, Existsè altrettanto conveniente ed espressivo come Any, con un predicato. L'uso della Count != 0proprietà su a Listè più normale dell'uso Any(). È solo una preferenza personale. Ho passato anche attraverso lo sforzo di cambiare _list_.Count()per _list_.Countnel codice del mio gruppo. Per me ha fatto una notevole differenza.
Suncat2000,

55

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


15
Count()inoltre non si fermerà per infiniti iteratori, mentre lo Any()farà, poiché deve solo chiamare MoveNext()una volta.
Jon Purdy,

3
Succinto e preciso, ma questo si legge più come un commento che come una risposta. I programmatori preferiscono le risposte che approfondiscono il perché e forniscono una misura di spiegazione. Valuta la possibilità di modificare la tua risposta e di ampliare il motivo per cui O (1) potrebbe essere (è) importante.

risposta molto buona appena appreso che dovrei usare qualsiasi invece di count == 0: d
MonsterMMORPG

4
Any(Func<T>)è O (n)
BlueRaja - Danny Pflughoeft il

1
Nel caso specifico di List, le prestazioni sono le stesse perché l'estensione utilizza la proprietà. Vero per tutte le raccolte che implementano l' ICollectioninterfaccia.
Thorkil Holm-Jacobsen,

9

In realtà, tenere presente che esiste la proprietà List.Count e quindi il metodo Enumerable.Count .

Nel tuo esempio, stai usando il Enumerable.Count()metodo, che deve scorrere attraverso ogni singolo elemento dell'enumerazione per restituire un risultato. Ciò è chiaramente più lento della chiamata, Any()che deve solo scorrere sul primo elemento, se esiste.

MODIFICARE:

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

Fonte IEnumerable.Count :

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

Giusto. Che dire dell'uso della proprietà .Count allora? ciò non renderebbe la lettura significativamente più veloce, forse più veloce o addirittura più veloce di chiamare .Any ()?
Gil Sand,

4
Con una List<T>differenza di prestazioni sarà trascurabile. Quindi usa solo quello che preferisci. Ma per altri tipi di IEnumerables, devi solo scegliere tra Count()(il metodo) e Any(), in tal caso, Any()sarà sempre il chiaro vincitore per il tuo caso d'uso e dovrebbe essere preferito. Per quello che vale, penso che Any()sia abbastanza leggibile e chiaro.
sstan,

@sstan sì a meno che se l'enumerabile può essere lanciato su una collisione, allora può essere ottimizzato e non importa.
Esben Skov Pedersen,

2
Count()ha la stessa complessità di Countper ICollections, poiché il metodo di estensione utilizza quindi la proprietà anziché iterare.
Thorkil Holm-Jacobsen,

Le estensioni Linq sono ottimizzate per interfacce note: IList, ICollection. La discussione sulle prestazioni qui è totalmente ridondante, anche se si tratta di un dettaglio di implementazione
Gusdor,

6

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

Intento significa: se leggi il codice di qualcuno (e non lo hai scritto tu stesso), è del tutto ovvio ciò che il programmatore vuole ottenere e perché ha scritto così? Se un problema comune viene risolto in modo inutilmente complesso, si diventa immediatamente sospettosi e ci si chiede perché lo sviluppatore non abbia usato il modo semplice. Dai un'occhiata al codice e provi a vedere se hai perso qualcosa. Hai paura di cambiare il codice perché temi che manchi qualche effetto collaterale e la sua modifica potrebbe causare problemi imprevisti.

L'intento di utilizzare il Any()metodo è completamente chiaro: vuoi sapere se ci sono elementi nell'elenco o no.

L'intento dell'espressione Count()!=0invece non è ovvio per il lettore. Ovviamente non è difficile vedere che l'espressione ti dice se l'elenco è vuoto o no. Le domande sorgono perché lo scrivi in ​​questo modo particolare piuttosto che usare il metodo standard. Perché usi Count()esplicitamente? Se davvero solo bisogno di sapere se ci sono eventuali elementi di una lista, perché vuoi contare l'intero elenco prima? Non appena raggiungi 1 avrai già la tua risposta. Se la fonte fosse un iteratore su una grande raccolta (forse infinita) o fosse tradotta in sql, potrebbe fare una grande differenza in termini di prestazioni. Quindi forse l'uso esplicito di Count () è forzare l'esecuzione di una query differita 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 Countproprietà che indica più chiaramente che ti aspetti un'operazione O (1) senza effetti collaterali?

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


Ho letto entrambi come "l'elenco contiene elementi?" Count()ha una conversione implicita che eviterei di usare, ma non è poco chiaro. Il compilatore può ottimizzarlo via, il che lo rende solo un codice trascurato.
Suncat2000,

2

Forse è solo la parola? Anyè un aggettivo, non dire davvero nulla. Venendo da Java, lo chiamerei isNonEmptyche contiene un verbo. Un ragazzo SQL potrebbe preferire EXISTS. Ma forse si Anyadatta meglio al sistema C #.

Qualunque sia la parola scelta, una volta che ti ci abitui, deve essere molto più chiaro. Vuoi chiedere "Sono more than zerorimaste le bottiglie di birra"? Ti aspetteresti che le one or morepersone inizino a contarle prima di rispondere "No, non c'è any"?


1
Il nome "qualsiasi" ha senso quando ci pensi in termini di LINQ: Any()è davvero una scorciatoia perAny(o => true)
BlueRaja - Danny Pflughoeft

Normalmente non userei vuoto per descrivere se un enumerabile avesse qualcosa da elencare. Ma "c'è alcuna cosa per enumerare" sembra naturale per me, e le eventuali opere contro ogni enumerazione.
Andy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.