Я хочу сгруппировать список User
по их Group
.
Пользователь может быть в нескольких группах.
public class User
{
public string Username { get; set; }
public List<Group> Groups { get; set; }
}
BusinessLogic возвращает мне List<User>
.
Вместо того, чтобы пользователи имеют свои группы, мне нужно реформировать этот список, чтобы группы содержали пользователей.
Пример:
Группа 1:
- Пользователь 1
- Пользователь 2
Группа 2:
- Пользователь 1
- Пользователь 3
Группа 3:
- Пользователь 2
- Пользователь 3
Я застрял на том методе расширения, который мне нужно использовать, поэтому я не уверен, что искать.
Я бы предположил метод GroupBy
но после этого я потерялся :)
Используйте SelectMany
для сглаживания вложенных коллекций, извлекают кортежи пользователя и группы. Таким образом, использование, содержащее много групп, приведет к многократной записи. Следующая группа записывает группу и сохраняет пользователя в качестве элементов в группе
var result = userList.SelectMany(user => user.Groups.Select(group => (user,group)))
.GroupBy(item => item.group, item => item.User);
В текущей реализации, так как группа выполняется над объектом Group
, этот объект должен реализовывать Equals
и GetHashCode
. Если вы не хотите этого делать, существует перегрузка, которая также получает IEqualityComparer
. Подробнее см. В документации.
Обратите внимание на использование Named Tuples. Если вы используете С# до 7.0, вы можете спроектировать анонимный объект или явно инициализировать кортеж, а затем изменить способ доступа к свойствам - Item1
и Item2
.
Решение, предложенное в принятом ответе, не работает. Мое решение:
var result1 = from user in users
from grp in user.Groups
group user by grp into pivot
select pivot;
Исправлена версия кода Gilad:
var result = users.SelectMany(user => user.Groups,(user, group)=>(user,group))
.GroupBy(item => item.group,item=>item.user);
Полный код моего и Гилада:
static void Main(string[] args)
{
Group group1 = new Group("Group1");
Group group2 = new Group("Group2");
Group group3 = new Group("Group3");
List<User> users = new List<User>(new User[] {
new User() { Username = "User1", Groups = new List<Group>(new Group[] { group1,group2}) },
new User() { Username = "User2", Groups = new List<Group>(new Group[] { group1,group3}) },
new User() { Username = "User3", Groups = new List<Group>(new Group[] { group2,group3}) }
});
var result1 = from user in users
from grp in user.Groups
group user by grp into pivot
select pivot;
foreach (var r in result1)
{
Console.WriteLine(r.Key.Name);
foreach (var u in r)
Console.WriteLine(u.Username);
}
Console.WriteLine();
var result = users.SelectMany(user => user.Groups.Select(group => (user, group))
.GroupBy(item => item.group,item=>item.user));
foreach (var r in result)
{
Console.WriteLine(r.Key.Name);
foreach (var u in r)
Console.WriteLine(u.Username);
}
Console.ReadKey();
}
public class Group : IEquatable<Group>
{
public Group(string name)
{
Name = name;
}
public string Name { get; set; }
public bool Equals(Group other)
{
return other.Name == Name;
}
public override bool Equals(object obj)
{
return ((Group)obj).Name==Name;
}
public override int GetHashCode()
{
return Name.GetHashCode();
}
}
public class User
{
public string Username { get; set; }
public List<Group> Groups { get; set; }
}
Выход (сначала мой код, второй вывод кода Gilad):
Group1
User1
User2
Group2
User1
User3
Group3
User2
User3
Group1
User1
Group2
User1
Group1
User2
Group3
User2
Group2
User3
Group3
User3