Kevin Cruijssen
Kevin Cruijssen

Reputation: 9326

Each Property-Value in a MyObject-list must be unique

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

Answers (4)

Charmander
Charmander

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

Giorgi Nakeuri
Giorgi Nakeuri

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

Anton Gogolev
Anton Gogolev

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

Mat&#237;as Fidemraizer
Mat&#237;as Fidemraizer

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.

I might still need an ordered collection of elements

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

Related Questions