2013-08-28 12 views

risposta

29

È possibile controllare utilizzando All metodo, presumibilmente la vostra lista sono allievi:

var firstStudent = students.First(); 
students.All(s => s.Age == firstStudent.Age); 
+2

Probabilmente sarebbe meglio sollevare prima il 'First', anche se –

+0

La tua prima implementazione non è stata così male perché enumerare fino a quando il primo elemento non è costoso. –

+0

@MarcGravell: hai ragione, modificato –

7

Se si vuole fare questo in una query, non due (che è generalmente una cattiva pratica),

bool allAgesAreTheSame = (students.Select(s => s.Age).Distinct().Count() < 2); 

lo farà per voi.

Questo restituirà anche true nel caso banale in cui non ci sono studenti, piuttosto che lanciare un'eccezione. (Si potrebbe fare == 1 piuttosto che < 2 per restituire false nel caso banale, invece.)

+1

Un pensiero interessante: puoi aggiungere un 'Take (2)' tra 'Distinct()' e il 'Conteggio() ', che consentirebbe un livello di cortocircuito - tuttavia, avrebbe il sovraccarico di un iteratore aggiuntivo - quindi se questa è una buona cosa dipende dal fatto che un gran numero di età diverse sarebbe uno scenario probabile –

+0

@ Marc, buon punto, sono abbastanza deluso da me stesso nell'usare un "conteggio" quando in realtà voglio solo un "0", 1 o 2 "", di solito sono abbastanza bravo a individuare quella roba. – Rawling

+1

Questo wer iterate tutte le età anche se i primi due sono diversi. –

2

Basta una risposta a caso - non sono sicuro che farei in questo modo in realtà, ma questo sarà brutalmente efficace:

  • userà iteratori digitati se anatra tipizzazione è disponibile (a differenza di LINQ che non sarà) - e si noti che List<T>fa offrono anatra tipizzato iteratori
  • nessun doppio-iterazioni
  • fallimenti ecc per le sequenze vuote
  • non delegati, cattura-contesti, ecc
  • ecc

Codice:

using(var iter = students.GetEnumerator()) // a List<T>.Enumerator struct 
{ 
    if(!iter.MoveNext()) return true; // or false, as you define for "empty" 

    int age = iter.Current.Age; 
    while(iter.MoveNext()) 
     if(iter.Current.Age != age) 
      return false; 
    return true; 
} 
+0

+1 per "brutalmente efficiente". – Rawling

+0

@Rawling Sono così vecchio stile: p –

0

Se non è possibile utilizzare LINQ, si può sempre ad anello tutti gli studenti:

private bool sameAge (List<Student> students) 
{ 
    int auxAge = students.Count > 0? students[0].Age : 0; 

    foreach (Student stu in students) 
    { 
     if (stu.Age != auxAge) 
      return false; 
    } 
    return true; 
} 
3

Se gli studenti possono avere 0 elementi si può fare questo:

var firstStudent = students.FirstOrDefault(); 
var areSame =students.All(s => s.Age == firstStudent.Age); 
+2

@Rawling Ho provato la soluzione e ha fatto ** non ** un'eccezione perché se ci sono 0 elementi, il metodo All() restituirà true senza tentare di eseguire il predicato lambda! –

+0

... Ottimo punto, ora non mi sento stupido :) – Rawling

0

Se è sufficiente controllare questa volta, la risposta migliore è la soluzione migliore. Per usarlo più volte nel codice basta scrivere un'estensione statica per controllare l'uguaglianza della proprietà:

public static bool GetIdenticProperty<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> predicate) 
{ 
    IEnumerable<TSource> enumerable = source as IList<TSource> ?? source.ToList(); 
    if ((!enumerable.Any()) || (enumerable.Count() == 1)) 
     return true; // or false if you prefere 
    var firstItem = enumerable.First(); 
    bool allSame = enumerable.All(i => Equals(predicate(i), predicate(firstItem))); 
    return allSame; 
} 

Se si desidera utilizzare il valore della proprietà in seguito permette di restituire tale valore:

public static TKey GetIdenticProperty<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> predicate) 
{ 
    IEnumerable<TSource> enumerable = source as IList<TSource> ?? source.ToList(); 
    if (!enumerable.Any()) 
     return default(TKey); 
    var firstItem = enumerable.First(); 
    bool allSame = enumerable.All(i => Equals(predicate(i), predicate(firstItem))); 
    return allSame ? predicate(firstItem) : default(TKey); 
} 

Ma usando questo codice devi controllare che il valore restituito sia null o default(TKey) relativo al tipo di proprietà.

Problemi correlati