8
votes

Comment pouvez-vous commander une hiérarchie d'objets par niveau de profondeur à l'aide de LINQ?

considérer cette hiérarchie xxx

chaque objet a une propriété mère et une collection d'articles pour le cholorren, donc par exemple, e a un parent de B, N de H, etc. A a une valeur de null pour le parent. B.items contient D-F, etc.

Qu'est-ce qu'une déclaration LINQ que je peux trier ces niveaux par leur niveau? Je me fiche de l'ordre de tri dans un niveau (c'est-à-dire que l'ordre de DH n'a pas d'importance, mais ils doivent venir après B et C qui doivent venir après une.

Seulement, je peux pense que deux déclarations distinctes LINQ:

  1. Exécutez un agrégat sur ceci, calculer et stocker les niveaux comme vous allez
  2. Exécutez une deuxième requête LINQ sur les résultats commandés par niveau.

    B est facile bien sûr. C'est un endroit que je me débats. Je peux le faire procéduralement bien sûr, mais je dois penser que cela peut être réduit à une relève LINQ.


4 commentaires

Linq à quoi? Linq à SQL? Linq aux entités? Linq aux objets?


Je pense que vous pouvez utiliser la procédure de magasin pour la performance


Les parents connaissent-ils l'enfant?


@Sven, oui, les parents connaissent également leurs enfants via une propriété d'articles.


4 Réponses :


8
votes

Vous n'avez pas spécifié quelle est la cible de votre requête, il existe donc plusieurs réponses correctes:

  1. LINQ à SQL ou Linq aux entités - La prise en charge des requêtes récursives n'existe pas, vous deviez donc charger les données dans la mémoire et effectuer LINQ vers des objets d'objets ou utiliser une procédure stockée dans la base de données. (probablement en utilisant une expression de table commune). Vous pouvez également préparer une vue dans la base de données et la mapper sur votre modèle EF. P> li>

  2. linq aux objets est mieux adapté au travail, mais imo vous êtes toujours meilleur avec une méthode simple qui calculait la profondeur: p>

    var results = from item in data
                  let depth = GetDepth(item)
                  orderby depth descending
                  select item;
    


4 commentaires

RE Il serait facile d'écrire une seule linq à des objets à des objets si votre structure de données était différente et votre message de blog - il est facile d'écrire une seule linq à des objets pour n'importe quoi Si vous incluez «écrire votre propre méthode d'extension» dans ce ...


Les articles connaissent également leurs enfants. Chacun a un parent et une collection d'enfants appelés articles. Et quand une personne spécifie LINQ, non LINQ-TO-XXX, vous devez toujours supposer qu'ils veulent dire que System.Linq sur des objets. :)


Solution soignée, mais elle pourrait être améliorée si vous bfs le graphique juste une fois , attacher chaque nœud sa profondeur, puis en utilisant un simple Orderby (p => p.depth) .


Le graphique change constamment. Les nœuds sont ajoutés et supprimés tout le temps. Le problème est que les nœuds peuvent entrer en panne, c'est pourquoi j'ai besoin de cette fonction. Je peux garantir d'abord les nœuds inférieurs.



0
votes

Il y a quelques méthodes pour résoudre ce problème.

Tout d'abord, vous pouvez implémenter la méthode, F.e. asffflaTenenEnumerable code>. Imagerie, vous avez la classe arbores code> qui ont des données de nœud de type t code>. P>

déclare Classe aplatissé code>: p> xxx pré>

puis implémenter asffflaTenenumerable code>: p> xxx pré>

maintenant Vous pouvez trier les nœuds avec Simple La requête LINQ: P>

var result = obj.OrderBy(i => i.Key);


0 commentaires

2
votes

Bien que mes amis aient posté de bonnes réponses, je risquez de fournir une autre réponse. S'il est possible de modifier la structure des nœuds pour de meilleures performances, vous pouvez définir la propriété de profondeur pour chaque nœud une fois, puis triez-les en fonction de la propriété de profondeur.

SetDepths(rootNode, 1);


0 commentaires

0
votes

Plug Shameless - Vous pouvez ajouter mon paquet Nuget sur lequel j'ai travaillé appelé Treenumerable:

https://www.nuget.org/packages/trenumerable P>

https://github.com/jasonmcboyd/trenumerable P> blockQuote>

Vous devez implémenter une interface Itreewalker qui sait comment traverser votre arbre (deux méthodes). Une fois que vous faites cela, vous pouvez simplement faire cela: p>

// Pseudocode
TreeWalker walker = new TreeWalker();
IEnumerable<YourType> levelOrder = walker.LevelOrderTraversal(A);


1 commentaires

Je vais certainement vérifier cela! :)