94

I have a List(Of DateTime) items. How can I check if all the items are the same with a LINQ query? At any given time there could be 1, 2, 20, 50 or 100 items in the list.

GEOCHET
  • 21,119
  • 15
  • 74
  • 98
Saif Khan
  • 18,402
  • 29
  • 102
  • 147

5 Answers5

151

Like this:

if (list.Distinct().Skip(1).Any())

Or

if (list.Any(o => o != list[0]))

(which is probably faster)

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • 28
    Potentially easier to read with "All" instead of "Any". You may also want to use First() instead of [0] in case list access cannot be performed (IEnumerable). if (list.All(o => o == list.First())) { ... } – Graeme Wicksted Sep 08 '14 at 21:00
  • 4
    `list.Distinct().Skip(1).Any()` is no different than `list.Distinct().Count != 1` right? – Simon_Weaver Sep 17 '16 at 19:15
  • 1
    @GraemeWicksted the whole point of Any() is to be faster if one item is found that DOESN'T match. Then you stop evaluating the list. What IS slightly clearer though is `!(list.Any(o => o != list[0]))` which is true if there are no items that are different from the first one - i.e. if they're all the same – Simon_Weaver Sep 17 '16 at 19:21
  • 10
    @Simon_Weaver `Any()` is used to find at least 1 match while `All()` is used to ensure all items match. In either case, if a non-match is encountered in All or a match is found in Any, they will halt iteration. So `!(list.Any(o => o != list[0]));` and `list.All(o => o == list[0]);` will always have the same iteration count. Thus both will have about the same execution time. P.S. You are correct, in that `list.Distinct().Skip(1).Any()` is analogous to `list.Distinct().Count != 1` just be aware Count can be slower than Any (possibly even in this case) with > 1 element. – Graeme Wicksted Sep 19 '16 at 00:57
  • But count has to iterate over the entire distinct list. If you have more than 2 sets, it's slower. – Lee Louviere Sep 16 '19 at 15:53
17

I created simple extension method mainly for readability that works on any IEnumerable.

if (items.AreAllSame()) ...

And the method implementation:

    /// <summary>
    ///   Checks whether all items in the enumerable are same (Uses <see cref="object.Equals(object)" /> to check for equality)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="enumerable">The enumerable.</param>
    /// <returns>
    ///   Returns true if there is 0 or 1 item in the enumerable or if all items in the enumerable are same (equal to
    ///   each other) otherwise false.
    /// </returns>
    public static bool AreAllSame<T>(this IEnumerable<T> enumerable)
    {
        if (enumerable == null) throw new ArgumentNullException(nameof(enumerable));

        using (var enumerator = enumerable.GetEnumerator())
        {
            var toCompare = default(T);
            if (enumerator.MoveNext())
            {
                toCompare = enumerator.Current;
            }

            while (enumerator.MoveNext())
            {
                if (toCompare != null && !toCompare.Equals(enumerator.Current))
                {
                    return false;
                }
            }
        }

        return true;
    }
MSkuta
  • 1,630
  • 13
  • 19
  • 1
    Nice! Just wondering about the empty list implementation. I'm not sure if I would assume that an empty list means "all are the same" - feels like a case for the consumer to handle, so I think I'm going to throw if the list empty. "Are the apples the same? No clue, because there are no apples in the basket" – Dirk Boer Oct 18 '19 at 07:54
  • This extension does not work in cases where the IEnumerable contains null values. For this case I added `if (toCompare == null && enumerator.Current != null) { return false; }` – MatterOfFact Mar 12 '23 at 08:29
14

My variant:

var numUniques = 1;
var result = list.Distinct().Count() == numUniques;
Seva
  • 1,631
  • 2
  • 18
  • 23
  • 2
    I like this, it's very readable and shows intent compared to the skip1/any solution. – tkit Nov 29 '19 at 11:51
9

This is an option, too:

 if (list.TrueForAll(i => i.Equals(list.FirstOrDefault())))

It is faster than if (list.Distinct().Skip(1).Any()) , and performs similarly as if (list.Any(o => o != list[0])), however, the difference is not significant, so I suggest using the more readable one.

KungFury
  • 91
  • 1
  • 3
4

VB.NET version:

If list.Distinct().Skip(1).Any() Then

Or

If list.Any(Function(d) d <> list(0)) Then
jor
  • 2,058
  • 2
  • 26
  • 46