Josh
Josh

Reputation: 464

Combining property values from duplicates in list

I was curious as to the best way to combine properties from duplicate records in a list. For example:

 var res = new List<MyObjList> {
     new MyObj { Id = 1, Type = "Class", Current = "Math", New = "Science" },
     new MyObj { Id = 2, Type = "Class", Current = "Math", New = "Science" },
     new MyObj { Id = 1, Type = "Year", Current = "Freshman", New = "Sophomore" },
     new MyObj { Id = 3, Type = "Year", Current = "Junior", New = "Senior" }                         
 }

I'm looking for this result:

 var res = new List<NewObj> {
     new NewObj { Id = 1, Class = "Math", UpcomingYear = "Freshman" },
     new NewObj { Id = 2, Class = "Math", UpcomingYear = null },
     new NewObj { Id = 3, Class = null, UpcomingYear = "Senior" }                        
 }

Failed attempt:

 var newRes = res
      .GroupBy(x => x.Id)
      .Select(grp => new NewObj {
            ItemId = grp.Key.Id,
            Class = grp.Key.Type == "Class" ? grp.Key.Class : null,
            UpcomingYear = grp.Key.Type == "Year" ? grp.Key.UpcomingYear : null
});

The thing I don't quite understand is how to join duplicates by ID and create a new object with conditional property values (or combine properties from each duplicate).

Edit: Updated result type/object

Edit2: Updated with failed attempts

Thanks!

Upvotes: 0

Views: 166

Answers (2)

Mick
Mick

Reputation: 6864

How about...

const string ClassType = "Class";
const string YearType = "Year";
var newRes = res
    .Where(r => r.Type == ClassType)
    .Select(r => new
    {
        r.Id,
        Class = r.Current,
        UpcomingYear = res
            .Where(r2 => r2.Id == r.Id && r2.Type == YearType)
            .Select(r2 => r2.Current)
            .FirstOrDefault()
    })
    .Union(res
        .Where(r =>
            r.Type != ClassType &&
            !res.Any(r2 => r2.Id == r.Id && r2.Type == ClassType))
        .Select(r => new
        {
            r.Id,
            Class = default(string),
            UpcomingYear = r.New
        }));

foreach(var item in newRes)
{
    Console.WriteLine($"{item.Id}, '{item.Class}', '{item.UpcomingYear}'");
}

OUTPUT:

 1, 'Math', 'Freshman' 
 2, 'Math', '' 
 3, '', 'Senior'

Upvotes: 1

Arad
Arad

Reputation: 12695

Say you have a Person class with 2 properties: FirstName and LastName.

And you have a list of people, you want to combine those who have the same FirstName and LastName (i.e. remove duplicates).

You could use LINQ's GroupBy method, like the following example:

List<Person> people = new List<Person> {
    new Person 
    {
        FirstName = "Arad",
        LastName = "Aral"
    },
    new Person
    {
        FirstName = "Arad",
        LastName = "Aral"
    }
};

List<Person> duplicatesRemoved = people.GroupBy(p => p.FirstName + p.LastName).Select(g => g.First()).ToList();

Now, our new list duplicatesRemoved is as follows:

List<Person> people = new List<Person> {
    new Person 
    {
        FirstName = "Arad",
        LastName = "Aral"
    }
};

Upvotes: 0

Related Questions