Je sais que je peux faire le ci-dessous avec une foreach mais me demandait s'il y a une façon propre et "plus sexy" de le faire avec Linq.
var result = (from t in items
group t by new {t.net, t.total}
into grp
select new
{
NET_GRAND = grp.Sum(t => t.net),
TOTAL_GRAND = grp.Sum(t => t.total)
}).GroupBy(x => new { x.NET_GRAND, x.TOTAL_GRAND }).ToList();
6 Réponses :
On dirait que vous voulez vraiment:
var netGrand = items.Sum(t => t.net); var totalGrand = items.Sum(t => t.total);
Salut Jon, cela fera-t-il une itération pour chaque variable? c'est-à-dire si nous avons un gros objet deviendra-t-il inefficace?
@Jon: Cela ira au fil de la liste deux fois, oui. Mais "inefficace" est un terme relatif - ce qui vous intéresse est de savoir s'il est rapide assez i>.
Dans la plupart des cas, oui, mais ce n'est plus concis que l'original Version code>. Alors que "assez rapide" est une bonne métrique lors de la comparaison des approches qui diffèrent sur d'autres motifs, il semble que cela ressemble ici à ce que cela choisirait quelque chose avec une performance clairement plus pauvre sans rien obtenir.
@Adamrobinson: éditera avec la version à deux variables distinctes, que est i> plus concise :)
var item = new item(); item.net = items .Sum(x=>x.net); item.total = items.Sum(x=>x.total);
Pourquoi créez-vous une nouvelle instance de élément code>?
@Adam Robinson, parce que OP Vous voulez créer un nouvel article et remplir sa propriété, je ne sais pas pourquoi vous avez demandé cela? Y a-t-il une autre réponse ici sans créer une nouvelle instance d'article?
Si vous ne vous souciez pas de itération de la liste deux fois,
var i = items.Aggregate(new item(),
(accumulator, it) =>
new item
{
net = accumulator.net + it.net,
total = accumulator.total + it.total
}
);
+1 pour l'utilisation de agrégat code> (Je viens de terminer l'écriture de mon propre moment où j'ai vu cela affiché), bien que je puisse suggérer d'utiliser un autre type pour l'accumulateur pour le rendre explicite ce qui se passe. Il convient également de noter que cela n'est certainement pas "plus sexy" qu'un simple foreach code> dans ce cas particulier.
D'accord sur le non si sexy mais bien plus efficace si vous avez un objet avec un grand nombre de champs.
@Jon: De quelle manière est-ce plus efficace que le foreach code>? Cela fait la même chose que le foreach code> mais nécessite un objet intermédiaire supplémentaire et une invocation déléguée. Aucun de ceux-ci n'est particulièrement i> punissant d'une perspective de performance, mais ils ne le font certainement pas plus i> efficace. Je suis cependant d'accord que des réponses présentées ceci est celle que j'utilise.
@Adamrobinson Désolé pour la Miss Compréhension Je ne pense pas que ce serait plus efficace mais plus élégant avec "Linqyness", je ne voulais tout simplement pas faire plusieurs itérations de Linq si évitables .. ou juste pour les pêcher
item totals = new item
{
net = items.Sum(i => i.net),
total = items.Sum(i => i.total)
};
But keep in mind that this query will enumerate a list two times, so for a large list this would not so efficient as old good single foreach loop.
+1 pour souligner le fait (un peu évident) que cela nécessite deux travaux de traversée.
Utilisez la boucle de foresach. Vous déclarez que vous êtes préoccupé par l'efficacité, et même si vous n'étiez pas une raison pour l'écrire à l'aide de Linq juste pour utiliser Linq.
Une des choses que nous découvrons comme nous obtenons beaucoup plus d'expérience avec les programmes est que Juste parce que quelque chose se fait "l'ancienne façon" ne le rend pas mauvais. Et la conversion de la méthode New-Wiz-Bang ne le rend pas mieux. En fait, si vous avez du code travaillant à l'ancienne, la "mise à niveau" est une cause d'injection de défauts, sans aucun avantage. P>
Au mieux, cette méthode LINQ prendra 2 fois plus de temps à calculer. p> Je ne sais pas la méthode globale, mais il faudra clairement plus de temps. p> p>
Il n'y a pas d'avantage réel à utiliser une boucle ici sur somme code>. La somme est plus courte, plus concise, représente sémantiquement exactement l'opération qui doit être effectuée, effectue cette opération de manière assez efficace et sans frais généraux particulièrement importants. Il est fortement improbable que l'approche LINQ soit n'importe où près de 2 fois plus lentement. Ils effectueraient tous les deux une surcharge effectivement identique. Il y aurait une touche de frais généraux pour itérant la séquence deux fois et pour l'utilisation d'un délégué, mais les deux devraient être plutôt minimes.
Les deux requêtes LINQ ne doivent-elles pas être itinéraires deux fois sur la liste? Où la boucle de Foreach (ou A pour) le ferait-elle une fois? Afin de prendre le même temps, le Linq devrait itéruer deux fois plus vite. Le code de la boucle de Foreach est 1 ligne de code plus - et cette ligne de code n'est nécessaire que si vous souhaitez créer un objet avec les résultats. Sinon, il utilise un + = = dans la boucle au lieu d'A = itemsum.sum. BTW: J'utilise Linq tout le temps, alors je suis d'accord que c'est une solution agréable et concise d'écrire du code. Mon seul point est qu'il est plus lent. (Je travaille avec le code de haute performance.)
C'est fait i> le travail deux fois plus vite, et c'est parce que cela fait la moitié du travail. Lequel de ces extraits de code est plus rapide: 1) foreach (Var item in List) {fil.sleep (1000); thread.sleep (1000);} code> 2) foreach Liste) thread.sleep (1000); foreach (Var item in List) thread.sleep (1000); code>? Une boucle qui effectue deux ajouts par itération va prendre deux fois plus longtemps que deux boucles effectuant un ajout par itération.
En termes de synchronisation, je m'attends à ce que la valeur d'itérateur suivante est le sommeil (1000), en tant que var + = valeur (avec le compilateur qui pose que dans un registre) va prendre 1 NS. Ou moins de temps réel, vs appelant un itérateur pour obtenir l'objet suivant dans une liste. Vient d'écrire un programme pour le tester: Temps en utilisant Linq: 0.947901695658294Ms Temps en utilisant pour: 0.496631422516865MS
Timer.Start (); var i = nouveau foo () {VAL1 = foasum.sum (it => it.val1), val2 = foasum.sum (it => it.val2)}; minuterie.stop (); Console.writeline (@ "Utilisation de Linq: {0} MS", Timer.DurationMilli); Timer.Start (); Foo résultantfoo = nouveau foo (); foreach (foo f in bulle) {résultatfoo.val1 + = f.val1; résultantfoo.val2 + = f.val2; }; minuterie.stop (); Console.writeline (@ "temps en utilisant pour: {0} MS", Timer.DurationMilli);
(Serait bien de pouvoir formater le code dans les commentaires :-(
Si vous modifiez les valeurs à ajouter à LIPS et modifiez la liste en une matrice, vous pouvez obtenir LINQ à une boucle de 7% de 7%, ce qui est meilleur que prévu. Si vous utilisez une liste <> et des valeurs longues, il reste encore 40% plus lent.
BTW, j'étais arrondi lorsque j'ai dit le mieux serait 2x, 1,9 est la valeur réelle de mon test d'origine.
LOL a fait voté par une "nouvelle technologie" junkie qui ne comprend pas les systèmes de haute performance. Je travaille avec le système noté à 1 000 000 utilisateurs simultanés et je ne peux même pas me permettre de réduire de 7%. Mon commentaire complet était relatif à la performance, et c'est la seule chose que je m'adresse ici. J'utilise aussi Linq. Bon chagrin.
Une grande partie des frais généraux de Linq va être constante, et non sur la taille du contenu. Bien sûr, interroger une liste de mémoire avec 10 éléments pourrait facilement prendre un grand pourcentage i> plus longtemps, mais la valeur absolument de la différence est également entièrement négligeable, car elle prend 40% de plus pour résumer les éléments d'une liste minuscule est toujours une opération entièrement négligeable. Bien sûr, pour une personne qui effectue un calcul suffisamment coûteux pour vraiment, et pour lesquelles ils ont été testés à fond et ont été trouvés en évitant que Linq soit un écaillage notable, c'est bon. Cela n'arrivera tout simplement pas.
Laissez-nous Continuez cette discussion dans le chat .
Je pense que vous pouvez accomplir cela à l'aide de Linq sans itération deux fois en utilisant GroupBy avec une valeur constante pour la clé (dans ce cas, j'utilise 1).
item totals = items.GroupBy(i => 1).Select(g => new item()
{
net = g.Sum(i => i.net),
total = g.Sum(i => i.total)
}).Single();
La solution la plus efficace est celle que vous avez déjà. Toute solution à base de Linq ici utilisera LINQ uniquement pour l'utilisation de LINQ.