Agrupar por LINQ em um objeto de dicionário

161

Estou tentando usar o LINQ para criar um Dictionary<string, List<CustomObject>>de a List<CustomObject>. Posso fazer isso funcionar usando "var", mas não quero usar tipos anônimos. Aqui está o que eu tenho

var x = (from CustomObject o in ListOfCustomObjects
      group o by o.PropertyName into t
      select t.ToList());

Eu também tentei usar a Cast<>()partir da biblioteca LINQ depois de terx , mas recebo problemas de compilação com o objetivo de ser uma conversão inválida.

Atari2600
fonte
E se você tentar var x = (de CustomObject o no grupo ListOfCustomObjects o por o.PropertyName em t selecione t) .ToList ();
esastincy
44
Existe alguma razão pela qual você precisa fazer isso em vez de usar o ToLookup, projetado para isso?
Jon Skeet
1
Jon, você poderia postar um exemplo de como o ToLookup funciona nessa situação? Não estou familiarizado com esse método LINQ.
Atari2600 15/06/11
8
@JonSkeet Você é demais! (Quero dizer, todo mundo já sabia disso, mas ainda assim.) A razão pela qual eu não estava pensando em usar o ToLookup era porque nunca tinha ouvido falar dele até agora. Agora eu sei!
neminem
1
Por uma questão de completude, o uso varnão está usando um tipo "anônimo", está usando um tipo "implícito". Tipos anônimos são novas classes criadas pelo compilador para manipular a construção new { thing = "stuff" };. Tipos implícitos são classes existentes, varé apenas uma maneira conveniente de referenciá-los quando a variável está sendo atribuída imediatamente; o tipo de variável pode ser deduzido do tipo de objeto que está sendo atribuído a ela. Você pode digitar até mesmo implicitamente uma variável referência a um tipo anônimo, ou seja:var a = new { thing = "stuff" };
Michael Blackburn

Respostas:

350
Dictionary<string, List<CustomObject>> myDictionary = ListOfCustomObjects
    .GroupBy(o => o.PropertyName)
    .ToDictionary(g => g.Key, g => g.ToList());
Yuriy Faktorovich
fonte
6
A menos que você esteja precisando de uma propriedade de 'CustomObject' como o valor da lista (não mostrado nesta resposta), vale a pena conferir o comentário de Jon Skeet sobre a delicadeza dele à pergunta que recomenda ToLookup ().
Shaun
3
esta é a maneira de fazê-lo se um resultado não imutável for desejado. ToLookup é imutável.
Amit
1
Meus 2 centavos (só porque me manteve lutando por uma hora :)): ao agrupar por uma propriedade, verifique se a propriedade possui um valor! Caso contrário, o método Todict falhar chave geração (para String-Propriedades, pelo menos ...) :)
dba
.GroupBy(o => o.PropertyName).ToDictionary(g => g.Key, g => g.ToList())Isso pode fazer parte da extensão Linq library. então só temos que fazer.ToDictionary(o=>o.PropertyName)
Jaider
3
@ Jaider, já existe essa funcionalidade: basta substituir ToDictionarypor ToLookup.
Robert Synoradzki
19

Não posso comentar sobre @ Michael Blackburn, mas acho que você recebeu o voto negativo porque o GroupBy não é necessário neste caso.

Use-o como:

var lookupOfCustomObjects = listOfCustomObjects.ToLookup(o=>o.PropertyName);
var listWithAllCustomObjectsWithPropertyName = lookupOfCustomObjects[propertyName]

Além disso, eu já vi isso ter um desempenho melhor do que ao usar GroupBy (). ToDictionary ().

RuudvK
fonte
Eu estava realizando uma transliteração, não respondendo à pergunta da melhor maneira possível.
Michael Blackburn
1

Para @ atari2600, é assim que a resposta seria usando ToLookup na sintaxe lambda:

var x = listOfCustomObjects
    .GroupBy(o => o.PropertyName)
    .ToLookup(customObject => customObject);

Basicamente, ele pega o IGrouping e o materializa em um dicionário de listas, com os valores de PropertyName como a chave.

Michael Blackburn
fonte
Por que um voto negativo? Isso não é exato / responde à pergunta?
Michael Blackburn
1
Caso você tenha perdido, @RuudvK mencionou em sua resposta que ele suspeita que o voto negativo é porque o GroupBy é desnecessário. ToLookuptem uma sobrecarga que fará o trabalho.
Jeff B
Perdi essa resposta, obrigado por me marcar. Faz sentido, o agrupamento é sintaticamente desnecessário, eu estava deixando para fazer a transição da sintaxe da consulta para a sintaxe do método mais clara.
Michael Blackburn
GroupBy (a sobrecarga com apenas um parâmetro) retorna um IEnumerable <IGrouping <TKey, TSource >> o ToLookup subsequente e depois o transforma em um tipo bastante complicado que nem é semelhante a um IDictionary <TKey, IList <TSource>> apenas o ToLookup retorna o tipo apropriado.
Xtofs
-1

O seguinte funcionou para mim.

var temp = ctx.Set<DbTable>()
  .GroupBy(g => new { g.id })
  .ToDictionary(d => d.Key.id);
Leo Barbas
fonte