简体   繁体   中英

Linq sort by element in list

I have a List of People, and I need to sort this list by their role and create a comma separated string with the first name of the people.

Lets say that the People class is:

public class Person
{
     public string FirstName { get; set; }
     public string LastName { get; set; }
     public string Role { get; set; }
}

We have five different roles: Architects, Developer, Tester, BA and Designer.

The tricky part for me is that Architects need to be first in the group, followed by engineers and then the rest. How do we achieve this?

I tried using var groups = people.GroupBy(i => i.Role); . But I do not know how to sort on that. I would appreciate some help

Update 1

Thanks for everyone's help. First of all my sincere apologies. I had simplified my question a bit but I guess the way it was portrayed had changed the problem statement. There are 2 important things.

  1. Role is not a enum, its a string.
  2. There can be more Roles in the list its free-form textfield, but what we are only concerned about is Engineers and Architects. Rest of them can be in any order

I see two options:

  1. Make role a enum and order roles there for sorting:
enum Role {
    Architect = 1,
    Engineer = 2,
    // the rest of them
}

var groups = people.OrderBy(i => i.Role); // I think this will work
var groups = people.OrderBy(i => (int)i.Role); // an alternative 
  1. (less pretty) Make a Dictionary<string,int> that will assign an integer value to roles. Then you can order by those values:
var groups = people.OrderBy(i => roles[i.Role]);

It seems to me that this is a simple way to do it:

var people = new List<Person>()
{
    new Person() { FirstName = "A", Role = "Developer" },
    new Person() { FirstName = "B", Role = "Designer" },
    new Person() { FirstName = "C", Role = "Architect" },
    new Person() { FirstName = "D", Role = "Developer" },
};

int RolePriority(string role) =>
    role == "Architect" ? 0 : (role == "Developer" ? 1 : 2);

var ouput =
    from p in people
    group p.FirstName by p.Role into g
    orderby RolePriority(g.Key)
    select new
    {
        role = g.Key,
        names = String.Join(", ", g),
    };

This gives me:

输出

You can set the order of the roles by modifying the RolePriority local function.

After clarity on the question, I updated my answer, which now answers the question and also is extendable that you can specify more roles on the roleOrders list to have priority over the rest of the roles.

var roleOrders = new Dictionary<string, int>()
{
    { "Developer", 2 },
    { "Architect", 1 },
    // You can add more roles here for priority ordering
};

var roleNames = people.GroupBy(p => p.Role, p => p.FirstName)
    .OrderBy(r => roleOrders.TryGetValue(r.Key, out var order) ? order : int.MaxValue)
    .ToDictionary(
        g => g.Key,
        g => string.Join(", ", g));

You can use fluent API syntax of LINQ just like that:

var people = new List<Person>()
{
    new Person() { FirstName = "A", Role = "Developer" },
    new Person() { FirstName = "B", Role = "Designer" },
    new Person() { FirstName = "C", Role = "Architect" },
    new Person() { FirstName = "D", Role = "Developer" },
};

// sort this list by their role and create a comma separated string with the first name of the people
var result = people
    .GroupBy(p => p.Role)
    .Select(g => new { Role = g.Key, Names = string.Join(",", g.Select(c => c.FirstName)) })
    .OrderBy(c => c.Role)
    .ToList();

在此处输入图像描述

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