The term "LINQ to Objects" refers to the use of LINQ queries with any IEnumerable or IEnumerable<T> collection directly, without the use of an intermediate LINQ provider or API such as LINQ to SQL or LINQ to XML. You can use LINQ to query any enumerable collections such as List<T>, Array, or Dictionary<TKey,TValue>.
songs.UserSongs.GroupBy(x => x.User).Select(g => new SongsForUser()
{
User = g.Key,
Songs = g.Select(s => s.SongId).ToList()
});
I suspect you want:
var songsByUser = songs.UserSongs
.GroupBy(song => song.UserId, song => song.SongId)
.Select(g => new SongsForUser { User = g.Key,
Songs = g.ToList() });
To explain, after the GroupBy
you'll have a bunch of groups, where the key of each group is the user ID, and the values within the group are the song IDs:
Key = 1, Values = 1, 4, 12
Key = 2, Value = 95
Then you're just converting that into your SongsForUser
type. Note that you don't need to explicitly include the ()
when calling the constructor in an object initializer - it's implicit unless you need to specify constructor arguments.
You could do this all in one GroupBy
call, by the way:
var songsByUser = songs.UserSongs
.GroupBy(song => song.UserId, song => song.SongId,
(user, ids) => new SongsForUser { User = user,
Songs = ids.ToList() });
Personally I usually find a separate Select
call to be more readable.
You can also do all of this with a query expression:
var songsByUser = from song in songs.UserSongs
group song.SongId by song.UserId into g
select new SongsForUser { User = g.Key, Songs = g.ToList() };
EDIT: The above is "provider-neutral" but it sounds like it's not working with LINQ to Entities. You may be able to get it to work like this:
var songsByUser = songs.UserSongs
.GroupBy(song => song.UserId, song => song.SongId)
.AsEnumerable()
.Select(g => new SongsForUser { User = g.Key,
Songs = g.ToList() });
The AsEnumerable
call will force the grouping to be done in the database, but the final projection (including the ToList
call) to be done locally. You should check the generated SQL for efficiency though.
Lets say you have the following:
public class SongsForUser
{
public int UserId;
public List<int> Songs;
}
Then a function like this one here will do. The list is just there to have some data to test with.
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
contains 2 items of type SongsForUser afterwards.
One with user 1 and a list of songs containing 1, 4 and 12
and one with user 2 and a list of songs containing 95.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With