Utilizzo di Linq per raggruppare un elenco di oggetti in un nuovo elenco raggruppato di elenco di oggetti


149

Non so se questo è possibile in Linq ma qui va ...

Ho un oggetto:

public class User
{
  public int UserID { get; set; }
  public string UserName { get; set; }
  public int GroupID { get; set; }
}

Restituisco un elenco che potrebbe essere simile al seguente:

List<User> userList = new List<User>();
userList.Add( new User { UserID = 1, UserName = "UserOne", GroupID = 1 } );
userList.Add( new User { UserID = 2, UserName = "UserTwo", GroupID = 1 } );
userList.Add( new User { UserID = 3, UserName = "UserThree", GroupID = 2 } );
userList.Add( new User { UserID = 4, UserName = "UserFour", GroupID = 1 } );
userList.Add( new User { UserID = 5, UserName = "UserFive", GroupID = 3 } );
userList.Add( new User { UserID = 6, UserName = "UserSix", GroupID = 3 } );

Voglio essere in grado di eseguire una query Linq nell'elenco precedente che raggruppa tutti gli utenti per GroupID. Quindi l'output sarà un elenco di elenchi di utenti che contiene l'utente (se questo ha senso?). Qualcosa di simile a:

GroupedUserList
    UserList
        UserID = 1, UserName = "UserOne", GroupID = 1
        UserID = 2, UserName = "UserTwo", GroupID = 1
        UserID = 4, UserName = "UserFour", GroupID = 1
    UserList
        UserID = 3, UserName = "UserThree", GroupID = 2
    UserList
        UserID = 5, UserName = "UserFive", GroupID = 3
        UserID = 6, UserName = "UserSix", GroupID = 3

Ho provato a usare la clausola groupby linq ma questo sembra restituire un elenco di chiavi e non è raggruppato correttamente:

var groupedCustomerList = userList.GroupBy( u => u.GroupID ).ToList();

Risposte:


309
var groupedCustomerList = userList
    .GroupBy(u => u.GroupID)
    .Select(grp => grp.ToList())
    .ToList();

1
molto bello, proprio quello di cui avevo bisogno. grazie. facendo questo il modo imperativo fa schifo.
user1841243,

1
Funziona bene? perché sono usato in questo modo non ha funzionato. objModel.tblDonars.GroupBy (t => new {t.CreatedOn.Year, t.CreatedOn.Month, t.CreatedOn.Day}). Seleziona (g => new {tblDonar = g.ToList ()}). ToList ( ); questo non funziona ... puoi aiutare ...
Rajamohan Anguchamy,

con la tua soluzione funziona benissimo ma ho una domanda supponiamo nel gruppo fino a un valore di 8 e voglio solo bisogno in ogni gruppo con solo 6 take, quindi come posso farlo per favore fatemelo sapere.
coderwill

c'è un modo per elencare i nomi utente e gli ID utente separatamente dopo il raggruppamento per GroupID? come - {"1", [1, 2, 4], ["UserOne", "UserTwo", "UserFour"]} per groupID 1.
Ajay Aradhya

1
Attualmente il codice non funziona e provoca un errore se si tenta di eseguirne il cast al precedente tipo di elenco. Perché la restituzione di un elenco in select crea un elenco all'interno di un elenco che non è l'output desiderato qui. Per coloro che hanno problemi, posso suggerire: var groupedCustomerList = userList.GroupBy (u => u.GroupID) .Select (grp => grp.First ()). ToList ();
aliassce

36

Il vostro gruppo dichiarazione volontà gruppo per ID gruppo. Ad esempio, se poi scrivi:

foreach (var group in groupedCustomerList)
{
    Console.WriteLine("Group {0}", group.Key);
    foreach (var user in group)
    {
        Console.WriteLine("  {0}", user.UserName);
    }
}

dovrebbe funzionare bene. Ogni gruppo ha una chiave, ma contiene anche una IGrouping<TKey, TElement>che è una raccolta che ti consente di scorrere i membri del gruppo. Come accennato da Lee, puoi convertire ogni gruppo in un elenco se lo desideri davvero, ma se hai intenzione di iterarli su di essi secondo il codice sopra, non c'è alcun vantaggio reale nel farlo.


4

Per tipo

public class KeyValue
{
    public string KeyCol { get; set; }
    public string ValueCol { get; set; }
}

collezione

var wordList = new Model.DTO.KeyValue[] {
    new Model.DTO.KeyValue {KeyCol="key1", ValueCol="value1" },
    new Model.DTO.KeyValue {KeyCol="key2", ValueCol="value1" },
    new Model.DTO.KeyValue {KeyCol="key3", ValueCol="value2" },
    new Model.DTO.KeyValue {KeyCol="key4", ValueCol="value2" },
    new Model.DTO.KeyValue {KeyCol="key5", ValueCol="value3" },
    new Model.DTO.KeyValue {KeyCol="key6", ValueCol="value4" }
};

la nostra query linq appare come di seguito

var query =from m in wordList group m.KeyCol by m.ValueCol into g
select new { Name = g.Key, KeyCols = g.ToList() };

o per array anziché elenco come di seguito

var query =from m in wordList group m.KeyCol by m.ValueCol into g
select new { Name = g.Key, KeyCols = g.ToList().ToArray<string>() };

-1

Ancora vecchio, ma la risposta di Lee non mi ha dato il gruppo. Chiave come risultato. Pertanto, sto usando la seguente dichiarazione per raggruppare un elenco e restituire un elenco raggruppato:

public IOrderedEnumerable<IGrouping<string, User>> groupedCustomerList;

groupedCustomerList =
        from User in userList
        group User by User.GroupID into newGroup
        orderby newGroup.Key
        select newGroup;

Ogni gruppo ora ha una chiave, ma contiene anche un IGrouping che è una raccolta che ti consente di scorrere i membri del gruppo.


Questo risponde alla tua domanda, non alla domanda di OP. Vogliono solo un elenco di elenchi. Il tuo codice non lo fornisce.
Gert Arnold,

Ho pubblicato questa soluzione perché la risposta accettata sopra da @Lee non funziona durante l'iterazione in quanto non fornisce l' group.keyelemento durante l'iterazione nell'elenco raggruppato come mostrato nella risposta di @JohnSkeet. La mia risposta fornita non fornire l'elemento group.key quando l'iterazione. Quindi potrebbe aiutare gli altri a cadere nella trappola che le risposte fornite non funzionino come mostrato sopra. Quindi è solo un altro modo per ottenere l'elenco con il vantaggio di ottenere l'elemento group.key simile alla risposta accettata. Non capisci il tuo reclamo @GertArnold. (.net core 3.0)
datapool

Penso che l'intera domanda si basi sulla mancanza di comprensione di cosa IGroupingsia. Ecco perché OP scarta il proprio codice corretto in fondo, che è essenzialmente identico al tuo codice. Ecco perché accettano una risposta che fornisce esattamente ciò che chiedono. Ciò di cui hanno bisogno è una spiegazione, che JS ha sufficientemente fornito.
Gert Arnold,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.