ILookup contre IGrouping
Question
J'ai eu du mal à articuler les différences entre ILookup<TKey, TVal>
et IGrouping<TKey, TVal>
, et je suis curieux de savoir si je comprends bien maintenant. LINQ aggravé le problème en produisant des séquences d'articles de IGrouping
tout en me donnant une méthode d'extension de ToLookup
. On avait l'impression qu'ils étaient les mêmes jusqu'à ce que je regardais de plus près.
var q1 =
from n in N
group n by n.MyKey into g
select g;
// q1 is IEnumerable<IGrouping<TKey, TVal>>
Ce qui est équivalent à:
var q2 = N.GroupBy(n => n.MyKey, n => n);
// q2 is IEnumerable<IGrouping<TKey, TVal>>
Ce qui ressemble beaucoup à:
var q3 = N.ToLookup(n => n.MyKey, n => n);
// q3 is ILookup<TKey, TVal>
Ai-je raison des analogies suivantes?
- Un
IGrouping<TKey, TVal>
est un groupe unique (à savoir une séquence à clé), analogue àKeyValuePair<TKey, TVal>
dont la valeur est en fait une séquence d'éléments (plutôt que d'un seul élément) - Un
IEnumerable<IGrouping<TKey, TVal>>
est une séquence de ceux (semblable à ce que vous obtenez lorsque vous parcourez unIDictionary<TKey, TVal>
- Un
ILookup<TKey, TVal>
est plus comme unIDictionary<TKey, TVal>
dont la valeur est en fait une séquence d'éléments
La solution
Oui, tous ceux qui sont corrects.
Et ILookup<TKey, TValue>
étend également IEnumerable<IGrouping<TKey, TValue>>
de sorte que vous pouvez parcourir toutes les clés / paires de collecte ainsi que (ou au lieu de) juste à la recherche des clés particulières.
Je pense essentiellement de ILookup<TKey,TValue>
comme comme IDictionary<TKey, IEnumerable<TValue>>
.
Gardez à l'esprit que ToLookup
est une opération « faire maintenant » (exécution immédiate) alors qu'un GroupBy
est reporté. Comme il arrive, avec la façon dont « tirer LINQ » fonctionne, quand vous commencez à tirer IGrouping
s du résultat d'un GroupBy
, il doit lire toutes les données de toute façon (parce que vous ne pouvez pas changer le groupe à mi-chemin), alors que dans d'autres implémentations il peut être en mesure de produire un résultat de streaming. (Il ne en push LINQ,. Je pense LINQ aux événements être le même)
Autres conseils
Il y a une autre différence importante entre iLookup et IDictionary: l'ancien immuabilité impose en ce sens que ucune méthodes pour modifier les données (sauf si le consommateur effectue un casting explicite). En revanche, IDictionary a des méthodes comme « Ajouter », qui permettent de modifier les données. Ainsi, dans la perspective de programmation fonctionnelle et / ou la programmation parallèle, iLookup est plus agréable. (Je veux seulement il y avait aussi une version de iLookup qui affecte une seule valeur à une clé plutôt que d'un groupe.)
(. BTW, il semble intéressant de souligner que la relation entre IEnumerable et IList est un peu semblable à celle entre iLookup et IDictionary -. Le premier est immuable, celle-ci n'est pas)
GroupBy
et ToLookUp
a presque la même fonctionnalité SAUF ceci: Référence
GroupBy: L'opérateur retourne GroupBy groupes d'éléments basés sur certains valeur clé. Chaque groupe est représenté par IGrouping objet.
ToLookup: ToLookup est le même que GroupBy; la seule différence est l'exécution de GroupBy est différé tandis que l'exécution est ToLookup immédiate.
Permet d'effacer la différence en utilisant le code de l'échantillon. supposons que nous avons une classe représentant le modèle Person
:
class Personnel
{
public int Id { get; set; }
public string FullName { get; set; }
public int Level { get; set; }
}
après que nous définissons une liste de personnels
comme suit:
var personnels = new List<Personnel>
{
new Personnel { Id = 1, FullName = "P1", Level = 1 },
new Personnel { Id = 2, FullName = "P2", Level = 2 },
new Personnel { Id = 3, FullName = "P3", Level = 1 },
new Personnel { Id = 4, FullName = "P4", Level = 1 },
new Personnel { Id = 5, FullName = "P5", Level =2 },
new Personnel { Id = 6, FullName = "P6", Level = 2 },
new Personnel { Id = 7, FullName = "P7", Level = 2 }
};
Maintenant je dois obtenir le personnels
regroupés selon leur niveau. J'ai deux approche ici. en utilisant GroupBy
ou ToLookUp
. Si j'utilise GroupBy
, comme indiqué précédemment, il utilisera l'exécution différée, cela signifie que lorsque vous itérer la collection l'élément suivant peut ou ne peut pas être calculé jusqu'à ce qu'il soit nécessaire.
var groups = personnels.GroupBy(p => p.Level);
personnels.RemoveAll(p => p.Level == 1);
foreach (var product in groups)
{
Console.WriteLine(product.Key);
foreach (var item in product)
Console.WriteLine(item.Id + " >>> " + item.FullName + " >>> " + item.Level);
}
Dans le code ci-dessus, je tout d'abord regroupé les personnels
, mais avant itérer, j'ai enlevé quelques personnels
. Comme GroupBy
utilise l'exécution différée, de sorte que le résultat final ne comprend pas les éléments supprimés, parce que le regroupement sera de calcul, dans le point de foreach
ici.
Sortie:
2
2 >>> P2 >>> 2
5 >>> P5 >>> 2
6 >>> P6 >>> 2
7 >>> P7 >>> 2
Mais si je réécris le code ci-dessus comme ci-dessous: (notez que le code est identique au code précédent, sauf GroupBy
est remplacé par ToLookUp
)
var groups = personnels.ToLookup(p => p.Level);
personnels.RemoveAll(p => p.Level == 1);
foreach (var product in groups)
{
Console.WriteLine(product.Key);
foreach (var item in product)
Console.WriteLine(item.Id + " >>> " + item.FullName + " >>> " + item.Level);
}
ToLookUp
utilise une exécution immédiate, cela signifie que lorsque j'appelle la méthode de ToLookUp
, le résultat est généré et le groupe est appliqué, de sorte que si je supprimer tout élément de personnels
avant l'itération, cet effet habitude le résultat final.
Sortie:
1
1 >>> P1 >>> 1
3 >>> P3 >>> 1
4 >>> P4 >>> 1
2
2 >>> P2 >>> 2
5 >>> P5 >>> 2
6 >>> P6 >>> 2
7 >>> P7 >>> 2
Note:. GroupBy
et ToLookUp
retournent toutes deux différents types trop
Vous pouvez utiliser ToDictionary au lieu de ToLookup, mais vous devez faire attention à ceci: ( référence )
L'utilisation de ToLookup () est très similaire à celle de ToDictionary (), à la fois vous permettent de spécifier les sélecteurs clés, sélecteurs de valeur, et . comparateurs La principale différence est que ToLookup () permet (et attend) les clés en double, tandis que ToDictionary () ne fonctionne pas