0

I have a Class called Person

class Person() {
 string Name;
 string SSN;
}

as well as a List That Contains many common instances of the Person class that are duplicates. For Example

   Person.Name = "John";
   Person.SSN = "123456789";
   Person.Name = "John";
   Person.SSN = "123456789";
   Person.Name = "John";
   Person.SSN = "123456789";
   Person.Name = "John";
   Person.SSN = "123456789";
   Person.Name = "John";
   Person.SSN = "123456789";

I am trying to figure the syntax out for a Linq statement to just take one of the class objects in the List when common and add it to a new list.

List<Person> newPerson = new List<Person>();

newPerson.AddRange(person.GroupBy(x => x.Name, x => x.SSN).Select(grp => grp.ToList().First()).ToList());

Thanks

AC25
  • 413
  • 1
  • 7
  • 23
  • 1
    Can you explain your intent - *the syntax out for a Linq statement to just take one of the class objects in the List when common*? I have read it several times and still don't understand what you are trying to achieve – Sergey Berezovskiy Apr 14 '14 at 16:24
  • possible duplicate of [linq distinct or group by multiple properties](http://stackoverflow.com/questions/20582391/linq-distinct-or-group-by-multiple-properties) – Servy Apr 14 '14 at 16:24

2 Answers2

3

The best way to do this would be to implement equality (either in Person directly, or via an IEqualityComparer<Person>) and then do a Distinct. E.g.

class Person : IEquatable<Person> {
    // these should be properties, e.g. public string Name { get; set; }
    string Name;
    string SSN;
    public override int GetHashCode() {
        // XOR is not the best generally, but can work for something like this
        return Name.GetHashCode() ^ SSN.GetHashCode();
    }
    public override bool Equals(object other) {
        return Equals(other as Person);
    }
    public bool Equals(Person other) {
        return other != null && this.Name == other.Name && this.SSN == other.SSN;
    }
}


var newPerson = person.Distinct().ToList();
Tim S.
  • 55,448
  • 7
  • 96
  • 122
2

Your GroupBy syntax is slightly off, and you don't need all of those ToList calls:

newPerson.AddRange(person.GroupBy(x => new {x.Name, x.SSN})
                         .Select(grp => grp.First()));

or just

newPerson = person.GroupBy(x => new {x.Name, x.SSN})
                  .Select(grp => grp.First())
                  .ToList();

since you're starting with an empty list anyways.

Detailed explanation

Your original syntax:

.GroupBy(x => x.Name, x => x.SSN)

compiles becasue there's an overload for GroupBy that takes a lambda for the key selector and another lambda for the result selector. It essentially grouped your collection by Name but returned a collection of strings (extracting the SSN property)

What you want to do is to create an anonymous type representing your compound key:

.GroupBy(x => new {x.Name, x.SSN})
D Stanley
  • 149,601
  • 11
  • 178
  • 240