Ответ 1
songs.UserSongs.GroupBy(x => x.User).Select(g => new SongsForUser()
{
User = g.Key,
Songs = g.Select(s => s.SongId).ToList()
});
У меня есть данные, которые выглядят так:
UserId | SongId
-------- --------
1 1
1 4
1 12
2 95
У меня также есть следующий класс:
class SongsForUser
{
public int User;
public List<int> Songs;
}
Что бы я хотел сделать, это использовать LINQ для выбора из моих данных для создания коллекции объектов SongsForUser. Ниже я догадываюсь:
var userCombos = songs.UserSongs.Select(x => new SongsForUser() { User = x.UserId,
Songs = /*What goes here?*/ });
Как бы я начал заполнять список Songs
?
Таким образом, результатом должно быть два объекта SongsForUser. Для пользователя 1
у него будет 3 элемента в списке Songs
. Для пользователя 2
у него будет 1 элемент в списке Songs
.
songs.UserSongs.GroupBy(x => x.User).Select(g => new SongsForUser()
{
User = g.Key,
Songs = g.Select(s => s.SongId).ToList()
});
Я подозреваю, что вы хотите:
var songsByUser = songs.UserSongs
.GroupBy(song => song.UserId, song => song.SongId)
.Select(g => new SongsForUser { User = g.Key,
Songs = g.ToList() });
Чтобы объяснить, после GroupBy
у вас будет группа групп, где ключ каждой группы - это идентификатор пользователя, а значения внутри группы - это идентификаторы песен:
Key = 1, Values = 1, 4, 12
Key = 2, Value = 95
Затем вы просто конвертируете это в свой тип SongsForUser
. Обратите внимание, что вам не нужно явно включать ()
при вызове конструктора в инициализаторе объекта - он неявно, если вам не нужно указывать аргументы конструктора.
Вы можете сделать все это одним вызовом GroupBy
, кстати:
var songsByUser = songs.UserSongs
.GroupBy(song => song.UserId, song => song.SongId,
(user, ids) => new SongsForUser { User = user,
Songs = ids.ToList() });
Лично я обычно нахожу отдельный вызов Select
более читабельным.
Вы также можете сделать все это с помощью выражения запроса:
var songsByUser = from song in songs.UserSongs
group song.SongId by song.UserId into g
select new SongsForUser { User = g.Key, Songs = g.ToList() };
РЕДАКТОР: Вышеупомянутый "нейтральный поставщик", но похоже, что он не работает с LINQ to Entities. Вы можете заставить его работать следующим образом:
var songsByUser = songs.UserSongs
.GroupBy(song => song.UserId, song => song.SongId)
.AsEnumerable()
.Select(g => new SongsForUser { User = g.Key,
Songs = g.ToList() });
Вызов AsEnumerable
заставит группировку выполнить в базе данных, но конечная проекция (включая вызов ToList
) будет выполняться локально. Однако вы должны проверить сгенерированный SQL на эффективность.
Предположим, что у вас есть следующее:
public class SongsForUser
{
public int UserId;
public List<int> Songs;
}
Тогда функция, подобная этой, будет выполнена. Список есть некоторые данные для тестирования.
public void Group()
{
List<Tuple<int, int>> SongRelations = new List<Tuple<int, int>>();
SongRelations.Add(new Tuple<int, int>(1, 1));
SongRelations.Add(new Tuple<int, int>(1, 4));
SongRelations.Add(new Tuple<int, int>(1, 12));
SongRelations.Add(new Tuple<int, int>(2, 95));
var list = SongRelations.GroupBy(s => s.Item1)
.Select(r => new SongsForUser()
{
UserId = r.Key,
Songs = r.Select(t => t.Item2).ToList(),
});
}
list
содержит 2 элемента типа SongsForUser впоследствии.
Один с пользователем 1 и список песен, содержащих 1, 4 и 12
и один с пользователем 2 и список песен, содержащих 95.
В простейшем виде вы можете просто:
List<MapPoint> points = db.PropertyResearches.Where(a => a.deptId == 66).Select(x => new MapPoint { property = x.notes.Substring(0, 10), latitude = x.lat, longitude = [email protected] }).ToList();