8

say I have a list containing objects like this one:

public class Person
{
    private string _name; 
    private string _id;
    private int _age;

    public Person 
    {
    }

    // Accessors
}

public class ManipulatePerson
{
    Person person = new Person();
    List<Person> personList = new List<Person>;

    // Assign values

    private void PopulateList();
    {
        // Loop 
        personList.Add(person);

        // Check if every Person has a unique ID
    }
}

and I wanted to check that each Person had a unique ID. I would like to return a boolean true/false depending on whether or not the IDs are unique. Is this something I can achieve with LINQ?

Jack
  • 237
  • 1
  • 4
  • 14
  • 3
    Use group by http://stackoverflow.com/questions/7325278/group-by-in-linq – edc65 Feb 19 '16 at 15:13
  • 4
    Or else, use `Distinct` and `Count` if the number differs. But firstly, put your ID to be a property rather than private field. – Ian Feb 19 '16 at 15:13

4 Answers4

10

Note that you can even leverage directly an HashSet<>:

var hs = new HashSet<string>();
bool areAllPeopleUnique = personList.All(x => hs.Add(x.Id));

(and is the code that I normally use)

It has the advantage that on the best case (presence of some duplicates) it will stop before analyzing all the personList collection.

xanatos
  • 109,618
  • 12
  • 197
  • 280
7

I would use Distinct and then check against the counts for example:

bool bAreAllPeopleUnique = (personList.Distinct(p => p.ID).Count == personList.Count);

However as @Ian commented you will need to add a property to the Person class so that you can access the Id like so:

public string ID
{
    get { return _id; }
}

A 'nicer' way to implement this would be to add a method like so:

private bool AreAllPeopleUnique(IEnumerable<Person> people)
{
    return (personList.Distinct(p => p.ID).Count == personList.Count);
}

NOTE: The method takes in an IEnumerable not a list so that any class implementing that interface can use the method.

TheLethalCoder
  • 6,668
  • 6
  • 34
  • 69
1

One of best ways to do so is overriding Equals and GetHashCode, and implementing IEquatable<T>:

public class Person : IEquatable<Person>
{
     public string Id { get; set; }

     public override bool Equals(object some) => Equals(some as Person);
     public override bool GetHashCode() => Id != null ? Id.GetHashCode() : 0;
     public bool Equals(Person person) => person != null && person.UniqueId == UniqueId;
}

Now you can use HashSet<T> to store unique objects and it will be impossible that you store duplicates. And, in addition, if you try to add a duplicated item, Add will return false.

NOTE: My IEquatable<T>, and Equals/GetHashCode overrides are very basic, but this sample implementation should give you a good hint on how to elegantly handle your scenario.

You can check this Q&A to get an idea on how to implement GetHashCode What is the best algorithm for an overridden System.Object.GetHashCode?

Maybe this other Q&A might be interesitng for you: Why is it important to override GetHashCode when Equals method is overridden?

Community
  • 1
  • 1
Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
0

You can use GroupBy for getting unique items:

var result = personList.GroupBy(p=> p.Id)
                   .Select(grp => grp.First())
                   .ToList();
Sirwan Afifi
  • 10,654
  • 14
  • 63
  • 110