IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

comment remplacer un foreach par du LINQ ?


Sujet :

C#

  1. #1
    Membre habitué
    Inscrit en
    Novembre 2004
    Messages
    415
    Détails du profil
    Informations forums :
    Inscription : Novembre 2004
    Messages : 415
    Points : 138
    Points
    138
    Par défaut comment remplacer un foreach par du LINQ ?
    Bonjour,
    J'ai actuellement ceci qui fonctionne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public void func(Division[] divisions)
    {
        var currencies = new HashSet<string>(divisions.SelectMany(div => div.Locations).Select(e => e.CcyLoc));
        //currencies.UnionWith(new HashSet<string>(divisions.SelectMany(div => div.CurrencyCode)));
        //ou bien même
        //currencies.UnionWith(divisions.SelectMany(div => div.CcyDiv));
        foreach(CalcDivision div in divisions) {
            currencies.Add(div.CurrencyCode);
        }
    }
    Mais je ne comprends pas pourquoi je ne peux pas remplacer mon foreach par un des lignes commentée du dessus. Ça ne compile pas (invalid arguments).
    Voyez-vous le problème?
    D'avance merci,
    Julien

  2. #2
    Membre averti Avatar de Shivaneth
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    349
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 349
    Points : 341
    Points
    341
    Par défaut
    Bonjour,

    essaye ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        var currencies = new HashSet<string>(divisions.SelectMany(div => div.Locations).Select(e => e.CcyLoc));
        currencies.AddRange((from d in divisions select d.CurrencyCode).ToList());
        //ou
        currencies.AddRange(divisions.Select(d=>d.CurrencyCode));
    Shiv@ Skunk

  3. #3
    Membre chevronné
    Avatar de Sehnsucht
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Octobre 2008
    Messages
    847
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Lot et Garonne (Aquitaine)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Octobre 2008
    Messages : 847
    Points : 2 209
    Points
    2 209
    Par défaut
    @Shiva Skunk: et la méthode HashSet<T>.AddRange ; tu la sors du chapeau ?

    en partant du principe que CurrencyCode et CcyDiv sont bien des string ; le fait de faire un SelectMany dessus renvoie alors un IEnumerable<char> car SelectMany sert à "aplatir" une collection de collections (et un string est un IEnumerable<char>) ; comme tu l'as fait pour "aplatir" l'ensemble des CcyLoc contenus dans tous les Locations. Du coup, a priori (parce qu'il faut quand même faire pas mal de "divination" pour savoir qui fait quoi avec le peu d'infos ), remplace ces SelectMany par des Select et ça devrait aller (il faudra peut-être un ajout de Cast ou OfType pour le CurrencyCode vu qu'il semblerait que tu l'obtiennes de CalcDivision plutôt que Division [et que je suppose que le premier hérite du second]).

    Sur un autre plan, le foreach c'était déjà très bien à la base ; faut arrêter de vouloir à tout prix mettre du Linq parce que c'est "hype" (UnionWith fait juste un foreach avec un AddIfNotPresent (une méthode interne à la classe) même méthode appelée depuis Add ; donc tu gagnes juste un passage par Add).

    Cordialement !
    Nous sommes tous plus ou moins geek : ce qui est inutile nous est parfaitement indispensable ( © Celira )
    À quelle heure dormez-vous ?
    Censément, quelqu'un de sensé est censé s'exprimer sensément.

  4. #4
    Membre averti Avatar de Shivaneth
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    349
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 349
    Points : 341
    Points
    341
    Par défaut
    Rho bah si on peut plus se réveiller tranquillement le matin aussi

    désolée :red:
    Shiv@ Skunk

  5. #5
    Membre éprouvé Avatar de worm83
    Homme Profil pro
    Architecte logiciel
    Inscrit en
    Février 2010
    Messages
    459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte logiciel
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2010
    Messages : 459
    Points : 1 118
    Points
    1 118
    Par défaut
    Bonjour,

    Tu peux recréer la méthode d'extension ForEach comme ceci

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
     
     public static void Foreach<T>(this IEnumerable<T> li, Action<T> action)
            {
                foreach (var x in li)
                {
                    action(x);
                }
            }


    Ce qui donne à l'utilisation

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
     
    public void UneAction(IEnumerable<string> li)
    {
           li.ForEach( x => Console.Writeline(x));
    }
    Ça reste un foreach mais écrit de facon "Linq".


    Edit : Je viens de remarquer que tu avais déjà posté la question et que quelqu'un avait répondu la même chose que moi.
    "Le train de tes injures roule sur le rail de mon indifférence."

    "Monde de merde !!"

    Georges Abitbol.

  6. #6
    Membre habitué
    Inscrit en
    Novembre 2004
    Messages
    415
    Détails du profil
    Informations forums :
    Inscription : Novembre 2004
    Messages : 415
    Points : 138
    Points
    138
    Par défaut
    C'est pas que je cherche à faire du LINQ à tout prix, je cherche juste à comprendre.
    Effectivement, je me suis trompé: CcyLoc, CurrencyCode et CcyDiv sont les mêmes string en fait mais je ne peux plus modifier mon post.
    AddRange n'est effectivement pas accessible.
    Effectivement Select fonctionne quand SelectMany ne fonctionne pas, c'est un peu tricky cette "mise à plat" que fait SelectMany pour passer d'un type string à un IEnumerable de char.. Dans ma 1ère ligne "SelectMany(div => div.Locations)", comment est-ce qu'il sait qu'il ne doit s'arrêter à retourner des Locations et pas d'autres types qui composent mes Locations?
    Y a-t-il une différence à faire currencies.UnionWith(new HashSet<string>(divisions.Select(div => div.CurrencyCode))); ou currencies.UnionWith(divisions.Select(div => div.CurrencyCode)); ?

  7. #7
    Membre chevronné
    Avatar de Sehnsucht
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Octobre 2008
    Messages
    847
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Lot et Garonne (Aquitaine)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Octobre 2008
    Messages : 847
    Points : 2 209
    Points
    2 209
    Par défaut
    Non ce n'est pas "tricky" c'est le boulot de SelectMany ; pour Locations si tu utilisais Select(div => div.Locations) tu obtiendrais comme résultat un IEnumerable<List<Location>> (en supposant que Locations a pour type List<Location>) avec SelectMany c'est comme si tu parcourrais chacune de ces List<Location> et pour chaque élément (chaque Location donc) tu la renvoyais dans un seul IEnumerable (ce qui donne donc comme résultat un IEnumerable<Location>) ; sans ça sur des scenarii complexes tu risquerais de te retrouver à un moment avec un IEnumerable<IEnumerable<... <IEnumerable<truc>... >> sans possibilité simple de manipuler les "truc" directement.
    Là où t'as "pas de bol" c'est que String implémente IEnumerable<char> (parce qu'après tout une chaine c'est une séquence de caractères) et donc quand tu utilises SelectMany(arg => arg.TrucRenvoyantString) le compilo applique les mêmes règles que précédemment et donc la seule possibilité c'est de considérer String en tant que IEnumerable<char> et donc tu te retrouvais ensuite avec l'incompatibilité de types que tu avais (Hashset<string>.UnionWith(IEnumerable<char>)).

    La différence entre les 2 façons ? créer un HashSet pour rien le constructeur de HashSet utilise UnionWith en interne donc en l'état c'est un UnionWith avec un truc vide puis UnionWith entre tes 2 HashSet au lieu de juste un UnionWith.
    Après si dans ta 2ème collection il y a beaucoup de doublons entre eux ils seront supprimés plus tôt (dans le UnionWith du constructeur) mais comme au final ils seront supprimés de toute façon
    Nous sommes tous plus ou moins geek : ce qui est inutile nous est parfaitement indispensable ( © Celira )
    À quelle heure dormez-vous ?
    Censément, quelqu'un de sensé est censé s'exprimer sensément.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. comment remplacer un foreach par du LINQ ?
    Par jmclej dans le forum Linq
    Réponses: 8
    Dernier message: 01/12/2014, 13h52
  2. [VB.NET] Comment remplacer une couleur par une autre?
    Par jazz matazz dans le forum VB.NET
    Réponses: 5
    Dernier message: 11/02/2006, 14h29
  3. Comment remplacer le clavier par des boutons ?
    Par aliwassem dans le forum Langage
    Réponses: 1
    Dernier message: 14/12/2005, 19h00
  4. Réponses: 5
    Dernier message: 30/05/2005, 16h58

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo