Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Abonnements

LINQ : une nouvelle façon de concevoir les algorithmes

Il y a plusieurs façon d'optimiser le code :

  • Faire le code le plus rapide à l'exécution
  • Faire le code le plus rapide à l'écriture
  • Faire le code le plus lisible
  • etc.

Comme l'optimisation est donc une notion très relative, je ne vais pas m'en soucier dans les requêtes LINQ suivantes.

Imaginons le cas suivant : 

private const string displayXml = @"<?xml version=""1.0"" encoding=""UTF-8""?><Displays><Display>Address1</Display><Display>TheatreName</Display><Display>Address2</Display><Display>City</Display></Displays>";

et un résultat :

string result = @"<NewDataSet>

                <SearchResults>

                  <TheatreID>3528</TheatreID>

                  <TheatreName>AMC OAK PARK PLAZA 6</TheatreName>

                  <Address1>9747 QUIVIRA RD</Address1>

                  <City>SHAWNEE MISSION</City>

                  <StateAbbr>KS</StateAbbr>

                  <ZipPlus4>66215</ZipPlus4>

                  <InterceptMarket>SHAWNEE MISSION</InterceptMarket>

                </SearchResults>

                <SearchResults>

                  <TheatreID>5135</TheatreID>

                  <TheatreName>AMC OAK TREE 6</TheatreName>

                  <Address1>10006 AURORA AVE N</Address1>

                  <City>SEATTLE</City>

                  <StateAbbr>WA</StateAbbr>

                  <ZipPlus4>98133</ZipPlus4>

                  <InterceptMarket>SEATTLE</InterceptMarket>

                </SearchResults>

                <SearchResults>

                  <TheatreID>7821</TheatreID>

                  <TheatreName>AMC OAKVIEW 24</TheatreName>

                  <Address1>3555 S 140TH PLZ</Address1>

                  <City>OMAHA</City>

                  <StateAbbr>NE</StateAbbr>

                  <ZipPlus4>68144</ZipPlus4>

                  <InterceptMarket>OMAHA</InterceptMarket>

                </SearchResults>

              </NewDataSet>";

On veut récupérer le résultat en fonction de sa constante : il fallait que les éléments soient classés dans le même ordre que dans sa constante.

La requête LINQ To XML suivante fera très bien l'affaire :

var newXml = new XElement("NewDataSet",

    from searchResult in XElement.Parse(result).Descendants("SearchResults")

    select new XElement("SearchResults",

        from display in XElement.Parse(displayXml).Descendants("Display")

        select searchResult.Element(display.Value)));

Complexifions un peu ça. Après avoir récupérer ces éléments displayXml, il faudrait rajouter les éléments non présents dans la constante. Comment faire ceci ?

La façon la plus naturelle, à mon sens, (avec LINQ) est la suivante :

var newXml = new XElement("NewDataSet",

    from searchResult in XElement.Parse(result).Descendants("SearchResults")

    let displayXmlElement = XElement.Parse(displayXml)

    select new XElement("SearchResults",

        (from display in displayXmlElement.Descendants("Display")

         select searchResult.Element(display.Value)).Union(

        from searchResultElement in searchResult.Elements().Select(sre => sre.Name.LocalName)

        where !displayXmlElement.Descendants("Display").Select(dxe => dxe.Value).Contains(searchResultElement)

        select searchResult.Element(searchResultElement))));

Petite remarque au passage, avec le constructeur du XElement, on peut se passer de l'Union :

var newXml = new XElement("NewDataSet",

    from searchResult in XElement.Parse(result).Descendants("SearchResults")

    let displayXmlElement = XElement.Parse(displayXml)

    select new XElement("SearchResults",

        from display in displayXmlElement.Descendants("Display")

        select searchResult.Element(display.Value),

        from searchResultElement in searchResult.Elements().Select(sre => sre.Name.LocalName)

        where !displayXmlElement.Descendants("Display").Select(dxe => dxe.Value).Contains(searchResultElement)

        select searchResult.Element(searchResultElement)));

Cependant, on peut également pensé autrement : mettre tous les éléments dans la constante puis remettre tous les éléments et enlever les doublons. Ce qui donne :

var newXml = new XElement("NewDataSet",

    from searchResult in XElement.Parse(result).Descendants("SearchResults")

    select new XElement("SearchResults",

        (from display in XElement.Parse(displayXml).Descendants("Display")

        select searchResult.Element(display.Value)).Union(searchResult.Elements()).Distinct()));

 

Cette dernière requête est beaucoup plus lisible que la précédente.Cependant, on peut également

 

Le but de post n'est bien entendu pas de montrer ce que tout le monde sait : pour un même problème, il y a plusieurs solutions. Le but recherché ici est de montrer comment LINQ permet de gagner en lisibilité avec du code "moins naturelle".

 

Prenons un autre exemple : dans Northwind, imaginons qu'on veuille récupérer pour chaque produit le client en ayant acheté la plus grande quantité avec la quantité.

 

Si on utilise LINQ en "mode algorithme classique", on va écrire la requête suivante :

 

from p in context.Products

let info = (from c in context.Customers

            let quantity =

                (from o in c.Orders

                 select

                    (from od in o.Order_Details

                     where od.Product == p

                     select (int)od.Quantity).Sum()).Sum()

            orderby quantity descending

            select new { Customer = c, Quantity = quantity }).First()

select new { Product = p, info.Customer, info.Quantity };

 

Si on utilise LINQ en "mode requête", on va plutôt écrire la requête suivante :

 

from p in context.Products

let info = (from od in p.Order_Details

            group od by od.Order.Customer into odByCust

            let quantity = odByCust.Sum(od => (int)od.Quantity)

            orderby quantity descending

            select new { Customer = odByCust.Key, Quantity = quantity }).First()

select new { Product = p, info.Customer, info.Quantity };

 

Après c'est à vous de décider vers quel critère d'optimisation vous voulez vous orienter.

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Publié vendredi 21 mars 2008 01:59 par Matthieu MEZIL

Classé sous : , , , ,

Commentaires

Pas de commentaires

Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- ProcDump 6.0 : support du filtrage sur messages d'exceptions .NET, des filtres multiples et du ciblage par nom de service par CoqBlog le il y a 6 heures et 38 minutes

- Votez pour le TOP 10 des influenceurs SharePoint francophones ! par Le blog de Patrick [MVP SharePoint] le il y a 8 heures et 29 minutes

- [Conf’SharePoint] Dernier rappel ! :-) par Le blog de Patrick [MVP SharePoint] le il y a 12 heures et 19 minutes

- [ #SharePoint 2013 ] les modèles de sites standards… par Le blog de Patrick [MVP SharePoint] le il y a 12 heures et 25 minutes

- 10 erreurs de compréhension concernant SharePoint… par Le blog de Patrick [MVP SharePoint] le il y a 13 heures et 1 minutes

- Conf’SharePoint : 10 bonnes raisons pour ne pas la rater par Le petit blog de Pierre / Pierre's little blog le 05-14-2013, 02:24

- [Event] Soirée de lancement Agile .NET France à Lyon par Blog Agile/ALM de Vincent THAVONEKHAM le 05-13-2013, 01:29

- .NET / Debug : inspection de la mémoire d'applications .NET (dump ou processus live) : première livraison d'une librairie .NET par Microsoft par CoqBlog le 05-11-2013, 22:21

- SharePoint : Incompatibilité avec Internet Explorer 10 (IE10) par Blog Technique de Romelard Fabrice le 05-08-2013, 16:29

- AutoSPInstaller pour SharePoint 2013 maintenant disponible en “RTM” par Julien Chable le 05-06-2013, 23:30