Linq (somme sans doublons)

cs_tulesais Messages postés 175 Date d'inscription mercredi 2 juin 2004 Statut Membre Dernière intervention 11 avril 2013 - 8 avril 2013 à 09:00
cs_tulesais Messages postés 175 Date d'inscription mercredi 2 juin 2004 Statut Membre Dernière intervention 11 avril 2013 - 11 avril 2013 à 14:48
Bonjour tout le monde !!!

je sais je sais ... c'est un problème de débutant ... faut bien commencer un jour non ??? :-)


j'ai la table suivante :

libelle montant
famille1 500€
famille2 1000€
famille3 800€
famille1 500€

je souhaiterais obtenir le montant total sans récupérer les doublons : soit 2300€ et non pas 2800€ (il ne faut prendre qu'un seul enregistrement pour la famille1)

je suppose qu'il faut utiliser un SUM avec count=1 mais je n'y arrive pas...

pourriez vous m'aider ???


merci d'avance pour votre aide !!!!!!!!!!!!

13 réponses

Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
8 avril 2013 à 18:00
Bonsoir et oui, il faut bien débuter.

Il y a cette page, pleine de petits exemples.

Entre autre Distinct...


Whismeril
0
krimog Messages postés 1860 Date d'inscription lundi 28 novembre 2005 Statut Membre Dernière intervention 14 février 2015 49
9 avril 2013 à 16:09
Salut,

La solution la plus simple et la plus performante est évidemment de faire un Distinct() sur ta liste et ensuite de faire la somme des éléments restants avec Sum().

Si tu ne connaissait pas la méthode Distinct, tu pouvais toujours créer une nouvelle liste dans laquelle tu mettais les éléments de la première liste s'ils n'y étaient pas déjà, puis faire la somme des éléments de cette deuxième liste. En gros, faire toi-même la méthode Distinct.

Sinon, tu peux aussi te débrouiller (mais de manière complexe, pas logique et lente) avec Sum et Count.
Dans ta méthode Sum, il faut définir un sélecteur. Au lieu de simplement faire elt => elt, si divises la valeur par son nombre d'occurrences dans la liste, tu auras le résultat que tu cherches. Dans ton exemple, on ajoute 500/2, 1000/1, 800/1 et 500/2.
De plus, il faut faire attention avec cette méthode à ne pas perdre la virgule en route lors des divisions, donc de faire un cast en double ou en float.

Krimog : while (!(succeed = try())) ;
- Nous ne sommes pas des décodeurs ambulants. Le style SMS est prohibé. -
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
9 avril 2013 à 17:37
Pourquoi faire simple quand on peut faire compliqué!


Whismeril
0
cs_tulesais Messages postés 175 Date d'inscription mercredi 2 juin 2004 Statut Membre Dernière intervention 11 avril 2013 2
11 avril 2013 à 09:46
merci beaucoup pour votre aide !!!

j'ai réussi à trouver la requête qui va bien par contre je n'arrive pas à l'exprimer en linq :-(

select sum(MONTANT) from Table A
where ID (select min(ID) from Table B where A.LIBELLE B.LIBELLE)

Est ce que cela est réalisable ???


Merci encore pour toute votre aide !!!
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
krimog Messages postés 1860 Date d'inscription lundi 28 novembre 2005 Statut Membre Dernière intervention 14 février 2015 49
11 avril 2013 à 10:46
Là, non seulement c'est se compliquer la vie, mais en plus, ce n'est pas réalisable si tu n'as pas d'ID, et enfin, ce n'est pas performant.

Comme on te l'a dit auparavant : d'abord tu fais un Distinct() et ensuite tu fais un Sum().

Krimog : while (!(succeed = try())) ;
- Nous ne sommes pas des décodeurs ambulants. Le style SMS est prohibé. -
0
cs_tulesais Messages postés 175 Date d'inscription mercredi 2 juin 2004 Statut Membre Dernière intervention 11 avril 2013 2
11 avril 2013 à 10:54
alors ...

pour le distinct (pas de message d'erreur) :

var w_Distinct = (
from w_Item in _ventilMaintMatColl
select w_Item.IdActivite
).Distinct().ToList();

pour le montant (la ca gueule sur le where) :

var w_Montant = (
from w_Item in _ventilMaintMatColl
where w_Item.Id == w_Distinct
select w_Item.MontantActivite
).Sum();

j'y suis presque ??? :-)
0
cs_tulesais Messages postés 175 Date d'inscription mercredi 2 juin 2004 Statut Membre Dernière intervention 11 avril 2013 2
11 avril 2013 à 11:10
j'ai pondu ca :


var w_Distinct = (
from w_Item in _ventilMaintMatColl
select new {montant = w_Item.MontantActivite}
).Distinct().ToList();
var w_Montant = (
from w_Item in w_Distinct
select w_Item.montant
).Sum();


je test et je vous tiens au courant !!!
0
cs_tulesais Messages postés 175 Date d'inscription mercredi 2 juin 2004 Statut Membre Dernière intervention 11 avril 2013 2
11 avril 2013 à 11:30
ca a l'air de fonctionner :-)

super !!!

ce fut dur mais j'y suis arrivé ... avec votre aide !!!


merci !!!
0
krimog Messages postés 1860 Date d'inscription lundi 28 novembre 2005 Statut Membre Dernière intervention 14 février 2015 49
11 avril 2013 à 11:47
Méthodes d'extension de LINQ :
int resultat _ventilMaintMatColl.Select(elt> elt.MontantActivite).Distinct().Sum();


Syntaxe de LINQ :
int resultat = (from elt in _ventilMaintMatColl select elt.MontantActivite).Distinct().Sum();


Krimog : while (!(succeed = try())) ;
- Nous ne sommes pas des décodeurs ambulants. Le style SMS est prohibé. -
0
cs_tulesais Messages postés 175 Date d'inscription mercredi 2 juin 2004 Statut Membre Dernière intervention 11 avril 2013 2
11 avril 2013 à 13:20
oups... chuis allé trop vite !!!

je présume que le premier distinct n'est pas ce que j'attend !!!
moi je veux faire un distinct sur IdActivite et non sur le montant

var w_Distinct = (
from w_Item in _ventilMaintMatColl
select new {montant = w_Item.MontantActivite}
).Distinct().ToList();
0
cs_tulesais Messages postés 175 Date d'inscription mercredi 2 juin 2004 Statut Membre Dernière intervention 11 avril 2013 2
11 avril 2013 à 13:25
c'est mieux ca krimog ?
(merci pour ta patience) :-)


var w_Distinct =
(
from w_Item in VentilMaintMatColl
select new { activite w_Item.IdActivite, montant w_Item.MontantActivite }
)
.Distinct().ToList();
0
krimog Messages postés 1860 Date d'inscription lundi 28 novembre 2005 Statut Membre Dernière intervention 14 février 2015 49
11 avril 2013 à 14:29
Au final, non, c'est pas mieux.
Si tu fais un new dans le select, le distinct ne marchera pas (puisqu'il va faire des objets avec des références différentes, donc le distinct va forcément toutes les garder).

Tu veux faire un Distinct sur le Montant, le Libellé, l'un ET l'autre ou l'un OU l'autre ?
Premier cas, CF pour précédent post.

Pour les autres, c'est plus complexe.

Je viens de faire une méthode d'extension (que je n'ai pas testé - vérifie donc que le résultat est bien celui attendu).
Il faut placer ça en dehors de ta classe :
public static class ExtensionMethods
{
        public static IEnumerable<T> Distinct<T>(this IEnumerable<T> collection, Func<T, T, bool> comparer)
        {
            List<T> list = new List<T>();
            foreach (T elt1 in collection)
            {
                if (!list.Any(elt2 => comparer(elt1, elt2))) list.Add(elt1);
            }
            return list;
        }
}

Cette méthode est une surcharge de la méthode Distinct, qui te permet de prendre tous les éléments d'une liste distincts, en utilisant ton délégué (comparer) comme comparateur.
Il crée une nouvelle liste vide. Il parcours ta liste (l'ancienne). Pour chaque élément, il regarde si la nouvelle liste a déjà un élément égal (selon le comparateur qu'on lui donne). Si non, il ajoute l'élément à la nouvelle liste.

Une fois que c'est fait :
// Distinct sur Libellé :
int montantTotal VentilMaintMatColl.Distinct((o1, O2)> (o1.IdActivite == o2.IdActivite)).Sum(o => o.MontantActivite);

// Distinct sur Montant et Libelle :
int montantTotal VentilMaintMatColl.Distinct((o1, o2)> (o1.IdActivite == o2.IdActivite && o1.MontantActivite == o2.MontantActivite).Sum(o => o.MontantActivite);

// Distinct sur Montant ou Libelle : 
int montantTotal VentilMaintMatColl.Distinct((o1, o2)> (o1.IdActivite == o2.IdActivite || o1.MontantActivite == o2.MontantActivite).Sum(o => o.MontantActivite);


Krimog : while (!(succeed = try())) ;
- Nous ne sommes pas des décodeurs ambulants. Le style SMS est prohibé. -
0
cs_tulesais Messages postés 175 Date d'inscription mercredi 2 juin 2004 Statut Membre Dernière intervention 11 avril 2013 2
11 avril 2013 à 14:48
wouah wouah wouah ... merci beaucoup :-)

je t'en dirais plus en début de semaine prochaine ! je n'aurais pas le temps de m'en occuper avant :-(

Merci encore pour toute ton aide et bon weekend ... en avance :-)
0
Rejoignez-nous