Agrupar por no LINQ

Vamos supor que se tivermos uma class como

class Person { internal int PersonID; internal string car ; } 

Agora eu tenho uma lista dessa class: List persons;

Agora essa lista pode ter várias instâncias com os mesmos PersonIDs, por exemplo:

 persons[0] = new Person { PersonID = 1, car = "Ferrari" }; persons[1] = new Person { PersonID = 1, car = "BMW" }; persons[2] = new Person { PersonID = 2, car = "Audi" }; 

Existe uma maneira que eu possa agrupar por personID e obter a lista de todos os carros que ele tem?

Por exemplo, o resultado esperado seria

 class Result { int PersonID; List cars; } 

Então, depois do agrupamento, eu teria:

 results[0].PersonID = 1; List cars = results[0].cars; result[1].PersonID = 2; List cars = result[1].cars; 

Pelo que fiz até agora:

 var results = from p in persons group p by p.PersonID into g select new { PersonID = g.Key, // this is where I am not sure what to do 

Alguém pode por favor me dizer a direção correta?

Absolutamente – você basicamente quer:

 var results = from p in persons group p.car by p.PersonId into g select new { PersonId = g.Key, Cars = g.ToList() }; 

Ou como uma expressão sem consulta:

 var results = persons.GroupBy( p => p.PersonId, p => p.car, (key, g) => new { PersonId = key, Cars = g.ToList() }); 

Basicamente o conteúdo do grupo (quando visto como um IEnumerable ) é uma seqüência de quaisquer valores que estavam na projeção ( p.car neste caso) presente para a chave dada.

Para mais informações sobre como o GroupBy funciona, veja meu post no Edulinq sobre o tópico .

(Eu PersonID para PersonId no exemplo acima, para seguir as convenções de nomenclatura do .NET .)

Como alternativa, você poderia usar uma Lookup :

 var carsByPersonId = persons.ToLookup(p => p.PersonId, p => p.car); 

Você pode então pegar os carros para cada pessoa com muita facilidade:

 // This will be an empty sequence for any personId not in the lookup var carsForPerson = carsByPersonId[personId]; 
 var results = from p in persons group p by p.PersonID into g select new { PersonID = g.Key, /**/car = g.Select(g=>g.car).FirstOrDefault()/**/} 
 var results = from p in persons group p by p.PersonID into g select new { PersonID = g.Key, Cars = g.Select(m => m.car) }; 

Você também pode tentar isso.

 var results= persons.GroupBy(n => new { n.PersonId, n.car}) .Select(g => new { g.Key.PersonId, g.Key.car)}).ToList(); 

experimentar

 persons.GroupBy(x => x.PersonId).Select(x => x) 

ou

para verificar se alguma pessoa está repetindo na sua lista tente

 persons.GroupBy(x => x.PersonId).Where(x => x.Count() > 1).Any(x => x) 

Eu criei um exemplo de código de trabalho com a syntax de consulta e método de syntax. Espero que ajude os outros 🙂

Você também pode executar o código no .net Fiddle aqui:

 using System; using System.Linq; using System.Collections.Generic; class Person { public int PersonId; public string car ; } class Result { public int PersonId; public List Cars; } public class Program { public static void Main() { List persons = new List() { new Person { PersonId = 1, car = "Ferrari" }, new Person { PersonId = 1, car = "BMW" }, new Person { PersonId = 2, car = "Audi"} }; //With Query Syntax List results1 = ( from p in persons group p by p.PersonId into g select new Result() { PersonId = g.Key, Cars = g.Select(c => c.car).ToList() } ).ToList(); foreach (Result item in results1) { Console.WriteLine(item.PersonId); foreach(string car in item.Cars) { Console.WriteLine(car); } } Console.WriteLine("-----------"); //Method Syntax List results2 = persons .GroupBy(p => p.PersonId, (k, c) => new Result() { PersonId = k, Cars = c.Select(cs => cs.car).ToList() } ).ToList(); foreach (Result item in results2) { Console.WriteLine(item.PersonId); foreach(string car in item.Cars) { Console.WriteLine(car); } } } } 

Aqui está o resultado:

 1
 Ferrari
 BMW
 2
 Audi
 -----------
 1
 Ferrari
 BMW
 2
 Audi

Tente isto:

 var results= persons.GroupBy(n => n.PersonId) .Select(g => new { PersonId=g.Key, Cars=g.Select(p=>p.car).ToList())}).ToList(); 

Mas no que diz respeito ao desempenho, a prática a seguir é melhor e mais otimizada no uso da memory (quando a nossa matriz contém muito mais itens como milhões):

 var carDic=new Dictionary>(); for(int i=0;i(){person.car}; } } //returns the list of cars for PersonId 1 var carList=carDic[1];