I have a nullable type, e.g. SomeEnum?
and a set of values, e.g. IEnumerable<SomeEnum?>
.
How to check that all items has the same value using LINQ (and get this value)?
I have a nullable type, e.g. SomeEnum?
and a set of values, e.g. IEnumerable<SomeEnum?>
.
How to check that all items has the same value using LINQ (and get this value)?
public static bool AllEqual<T>(this IEnumerable<T?> values) where T : struct
{
if (!values.Any()) return true;
T? first = values.First();
return values.Skip(1).All(v => first.Equals(v));
}
EDIT: To get the value you could return a tuple (success, value) like this:
public Tuple<bool, T?> AllEqual<T>(IEnumerable<T?> values) where T : struct
{
if(! values.Any()) return Tuple.Create(true, (T?)null);
T? first = values.First();
bool equal = values.Skip(1).All(v => v.Equals(first));
return Tuple.Create(equal, equal ? first : (T?)null);
}
or you could use an out parameter instead:
public static bool AllEqual<T>(this IEnumerable<T?> values, out T? value) where T : struct
{
value = null;
if (!values.Any()) return true;
T? first = values.First();
value = first;
return values.Skip(1).All(v => first.Equals(v));
}
!values.All()
do? –
Dementia !values.Any()
that checks for an empty sequence - this implementation assumes that all the items in an empty sequence are empty and the 'value' is null. You may want to throw an exception instead. values.All(...)
returns whether each item in the sequence meets some condition - in this case whether each other item is equal to the first (and hence are all equal). –
Low data.Distinct().Count() == 1;
works well too.
public static bool AllEqual<T>(this IEnumerable<T?> values) where T : struct
{
if (!values.Any()) return true;
T? first = values.First();
return values.Skip(1).All(v => first.Equals(v));
}
EDIT: To get the value you could return a tuple (success, value) like this:
public Tuple<bool, T?> AllEqual<T>(IEnumerable<T?> values) where T : struct
{
if(! values.Any()) return Tuple.Create(true, (T?)null);
T? first = values.First();
bool equal = values.Skip(1).All(v => v.Equals(first));
return Tuple.Create(equal, equal ? first : (T?)null);
}
or you could use an out parameter instead:
public static bool AllEqual<T>(this IEnumerable<T?> values, out T? value) where T : struct
{
value = null;
if (!values.Any()) return true;
T? first = values.First();
value = first;
return values.Skip(1).All(v => first.Equals(v));
}
!values.All()
do? –
Dementia !values.Any()
that checks for an empty sequence - this implementation assumes that all the items in an empty sequence are empty and the 'value' is null. You may want to throw an exception instead. values.All(...)
returns whether each item in the sequence meets some condition - in this case whether each other item is equal to the first (and hence are all equal). –
Low Lazy and returns true for empty sequences:
public static bool AllEqual<T>(this IEnumerable<T> source, out T value)
{
using (var enumerator = source.GetEnumerator())
{
if (!enumerator.MoveNext())
{
value = default(T);
return true;
}
value = enumerator.Current;
var comparer = EqualityComparer<T>.Default;
while (enumerator.MoveNext())
{
if (!comparer.Equals(value, enumerator.Current))
{
return false;
}
}
return true;
}
}
something.Select(...).AllEqual()
. The only problem here is that while it correctly returns true
for empty sequences, it also returns default(T)
for the value in that case, so an empty sequence is indistinguishable from a sequence full on nulls. It probably should have two out
parameters, the second one to say that there were elements in the first place. –
Ruggiero var value = data.Distinct().Single();
(which will throw an exception if there isn't exactly one unique value, otherwise it will return that value)
If you don't want exceptions:
var few=data.Distinct().Take(2).ToList();
if(few.Count==1) {
var value = few[0];
...
}
Take(2)
will throw an exception if Distinct()
returns 1-length collection, will it not? –
Dementia © 2022 - 2024 — McMap. All rights reserved.