简体   繁体   中英

How to concatenate multiple rows list with same value into single row

I have the following class called "Person".

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }    
    public string Hobby { get; set; }
}

I created a list with the following data:

List<Person> users = new List<Person>()
{
    new Person {Id= 1, Name = "Silva", Hobby = "Football" },
    new Person {Id= 2, Name = "Bob", Hobby = "Golf"},
    new Person {Id= 2, Name = "Bob", Hobby = "Tennis"},
    new Person {Id= 1, Name = "Silva", Hobby = "Sleeping"},
    new Person {Id= 3, Name = "Sue", Hobby = "Drinking"}
    new Person {Id= 1, Name = "Silva", Hobby = "Handball"},
    new Person {Id= 3, Name = "Sue", Hobby = "Football"},
};

Now I need to create a new list called "usersHobbies" that when called returns the following result.

Id    Name        Hobby 
1     Silva       Football, Sleeping, Handball   
2     Bob         Golf, Tennis
3     Sue         Drinking, Football             

You would use GroupBy() to achieve that. Group by Id , select the Name from the first group, use string.Join() to join the Hobbies into a single string:

var result = users.GroupBy(u => u.Id)  // group by Id
                  .Select(g => new     // select values
                  { 
                      Id = g.Key, 
                      Name = g.First().Name, 
                      Hobbies = string.Join(", ", g.Select(u => u.Hobby)) 
                  })
                  .ToList();

Output:

结果显示 3 行

If you want to return a new Person instead of an anonymous type, just update the Select :

 .Select(g => new Person
  { 
      Id = g.Key, 
      Name = g.First().Name, 
      Hobby = string.Join(", ", g.Select(u => u.Hobby)) 
  })

Update from your comment:

is it possible instead of string.join() to return a list or array

Yes, it is. Using an anonymous type:

var result = users.GroupBy(u => u.Id)  // group by Id
                  .Select(g => new     // select values
                  { 
                      Id = g.Key, 
                      Name = g.First().Name, 
                      Hobbies = g.Select(u => u.Hobby).ToList() 
                  })
                  .ToList();

Which returns a List<string> for Hobbies .

.GroupBy() has an override that lets you define a key selector, an element selector and the result selector ( docs ), which could suit your use case:

var result = users
    .GroupBy(
        u => new { u.Id, u.Name }, // key selector
        u => u.Hobby, // element selector
        (user, hobbies) => new Person { 
            Id = user.Id, 
            Name = user.Name, 
            Hobby = string.Join(", ", hobbies) })
    .ToList();

Here, (user, hobbies) are referencing the key selector and the element selector, respectively.

What happens is:

  • the users are grouped into unique users based on the combination of Id and Name (key selector)
  • the hobbies of each unique user are collected into an IEnumerable<string> (element selector)
  • for each unique user, a Person object is created and populated with all of the users hobbies.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM