15

So say I have a class Student with one property, int Age. Now if I have List<Student> students, how do I check if the age of all students in the list is equal?

user1151923
  • 1,853
  • 6
  • 28
  • 44
  • 1
    See http://stackoverflow.com/questions/5478681/using-linq-can-i-verify-a-property-has-the-same-value-for-all-objects – goodeye Oct 06 '14 at 16:50

6 Answers6

32

You can check by using All method, presumably your list have students:

var firstStudent = students.First();
students.All(s => s.Age == firstStudent.Age);
cuongle
  • 74,024
  • 28
  • 151
  • 206
11

If you want to do this in one query, not two (which is generally bad practice),

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

will do it for you.

This will also return true in the trivial case where you have no students at all, rather than throw an exception. (You could do == 1 rather than < 2 to return false in the trivial case instead.)

Rawling
  • 49,248
  • 7
  • 89
  • 127
  • 1
    An intersting thought: you could add a `Take(2)` between the `Distinct()` and the `Count()`, which would allow for a level of short-circuiting - however, it would have the overhead of an extra iterator - so whether this is a good thing depends on whether a large number of different ages would be a likely scenario – Marc Gravell Aug 28 '13 at 11:40
  • @Marc Good point, I'm quite disappointed in myself at using a `Count` when I really only want a "`0, 1 or 2`", usually I'm pretty good at spotting that stuff. – Rawling Aug 28 '13 at 11:44
  • 1
    This wil iterate all ages even if the first two are different. – Alex Siepman Aug 28 '13 at 11:49
  • 1
    @Alex Yup, Marc has already pointed this out, and a solution, and a caveat to why you might not want to use the solution, for which reason I've left the solution in his comment rather than copy it into my answer. I'd still take this over a two-query solution. – Rawling Aug 28 '13 at 11:54
4

Just a random answer - not sure I'd do it this way in reality, but this will be brutally efficient:

  • will use typed iterators if duck-typing is available (unlike LINQ which won't) - and note that List<T> does offer duck-typed iterators
  • no double-iterations
  • no failures etc for empty sequences
  • no delegates, capture-contexts, etc
  • etc

Code:

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;
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
3

If students can have 0 elements you can do this:

var firstStudent = students.FirstOrDefault();
var areSame =students.All(s => s.Age == firstStudent.Age);
Alex Siepman
  • 2,499
  • 23
  • 31
  • 2
    @Rawling I tested the solution and it did **not** throw an exception because if there are 0 elements, the All() method will return true without trying to execute the lambda predicate! – Alex Siepman Aug 28 '13 at 13:20
0

If you can't use linq, you can always loop all the students:

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;
}
SysDragon
  • 9,692
  • 15
  • 60
  • 89
0

If you just have to check this once, the marked answere is best solution. To use it multiple times in your code just write a static extension to check equality of property:

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

If you want to use the value of the property later on lets return that value:

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

But using this code you have to check weather the returnd value is null or default(TKey) relating to the type of property.

black.rook
  • 41
  • 5