Reputation: 9326
Let's say I have the following object:
public class MyObject
{
public string MyValue { get; set; }
}
And in another class I have a list of these objects:
public class MyClass
{
private List<MyObject> _list;
public MyClass(List<MyObject> myObjects)
{
_list = myObjects;
}
public bool AllUniqueValues()
{
...
}
}
I want to check if all MyObjects in the list have an unique (non-duplicated) Value
. When I use the following it works:
public bool AllUnique()
{
return _list.All(x => _list.Count(y => String.Equals(y.Value, x.Value)) == 1);
}
But I have the feeling this can be done easier / more elegant. So, my question, is there a better / more elegant approach to check if all MyObjects have a non-duplicated Value
, and if so, how?
Upvotes: 0
Views: 114
Reputation: 276
There are many ways to do it, but personally, I'd do the following:
public bool AllUnique()
{
return _list.GroupBy(x => x.MyValue).Count() == _list.Count();
}
Upvotes: 0
Reputation: 35780
One of many way to do it:
return !_list.GroupBy(c=>c.MyValue).Any(c=>c.Count() > 1);
At least it is a little bit more clear.
Upvotes: 1
Reputation: 115751
I find this quite elegant:
public static class EnumerableExtensions
{
public static bool AllUnique<TSource, TResult>(this IEnumerable<TSource> enumerable,
Func<TSource, TResult> selector)
{
var uniques = new HashSet<TResult>();
return enumerable.All(item => uniques.Add(selector(item)));
}
}
And now your code becomes:
var allUnique = _list.AllUnique(i => i.MyValue);
Upvotes: 3
Reputation: 64923
The most elegant way of solving this is using a set data structure. An unordered collection of unique elements. In .NET, you need to use HashSet<T>
.
You can either override Equals
and GetHashCode
of MyObject
to provide what equality means in your case, or implement an IEqualityComparer<T>
.
If you instantiate HashSet<T>
and you don't provide an IEqualityComparer<T>
implementation, then it will use your overrides, otherwise it will use the whole implementation. Usually you implement equality comparers if there're more than a meaning of equality for the same object.
If you still need to store your objects in order, you can both store the elements in both the HashSet<T>
and List<T>
in parallel. What you get with HashSet<T>
is a practically O(1)
access to your items when you need check if an item exists, get one or perform some supported operations in the collection, since it's a hashed collection, it won't need to iterate it entirely to find the element.
Upvotes: 0