2009-08-05 6 views
12

Je veux mettre en œuvre des divers algorithmes pour la pratique, juste pour voir à quel point je suis vraiment et mieux: pC#: Comment mettre en œuvre IOrderedEnumerable <T>

Quoi qu'il en soit, je pensais que je voudrais essayer d'utiliser IEnumerable<T> et IOrderedEnumerable<T> et d'autres types de collection .Net juste pour être compatible (de sorte que ce que j'écris peut être utilisé plus facilement plus tard).

Mais je ne trouve pas un moyen de renvoyer une instance de IOrderedEnumerable<T> autre que d'utiliser les méthodes d'extension OrderBy et ThenBy. Donc je suppose que je dois créer ma propre classe qui implémente cette interface. Mais l'interface n'a pas vraiment de sens pour moi d'être honnête. Cela pourrait, mais je ne suis pas sûr.

J'ai créé une classe vide, ajouté l'interface et j'ai demandé à ReSharper d'ajouter des implémentations vides pour moi. Il ressemble à ceci:

class MyOrderedEnumerable<T> : IOrderedEnumerable<T> 
{ 
    /// <summary> 
    /// Performs a subsequent ordering on the elements of an <see cref="T:System.Linq.IOrderedEnumerable`1"/> according to a key. 
    /// </summary> 
    /// <returns> 
    /// An <see cref="T:System.Linq.IOrderedEnumerable`1"/> whose elements are sorted according to a key. 
    /// </returns> 
    /// <param name="keySelector">The <see cref="T:System.Func`2"/> used to extract the key for each element.</param><param name="comparer">The <see cref="T:System.Collections.Generic.IComparer`1"/> used to compare keys for placement in the returned sequence.</param><param name="descending">true to sort the elements in descending order; false to sort the elements in ascending order.</param><typeparam name="TKey">The type of the key produced by <paramref name="keySelector"/>.</typeparam><filterpriority>2</filterpriority> 
    public IOrderedEnumerable<T> CreateOrderedEnumerable<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer, bool descending) 
    { 
     throw new NotImplementedException(); 
    } 

    /// <summary> 
    /// Returns an enumerator that iterates through the collection. 
    /// </summary> 
    /// <returns> 
    /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection. 
    /// </returns> 
    /// <filterpriority>1</filterpriority> 
    public IEnumerator<T> GetEnumerator() 
    { 
     throw new NotImplementedException(); 
    } 

    /// <summary> 
    /// Returns an enumerator that iterates through a collection. 
    /// </summary> 
    /// <returns> 
    /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection. 
    /// </returns> 
    /// <filterpriority>2</filterpriority> 
    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

Ce que je ne comprends pas est la méthode CreateOrderedEnumerable. Qu'est-ce que cela signifie exactement? Eh bien, je suppose que cela créerait un nombre ordonné, mais comment? L'algorithme de tri lui-même est-il censé y entrer? Et que va-t-il trier? Il n'y a pas de collection d'objets entrant dans cette méthode, alors où est-ce que cela signifie que la collection soit commandée? Comment utiliseriez-vous la classe? Est-il destiné à être implémenté comme une classe d'aide privée à l'intérieur de quelque chose qui a besoin de trier des choses?

Alors, au lieu d'un MyOrderedEnumerable<T> : IOrderedEnumerable<T>, vous pourriez avoir un QuickSorter<T> : IOrderedEnumerable<T> qui a une collection dans son constructeur et triée lorsque cette méthode CreateOrderedEnumerable a été appelé ... mais ce qui arriverait si quelqu'un a appelé GetEnumerator et a commencé à énumérer avant cette méthode avait été appelé?


Haha, je viens de découvrir avais demandé quelque chose de semblable il y a un moment here. Mais c'était à peu près si c'était possible d'en retourner un. Donc, je suppose que cette question est une réponse à la seule réponse que j'ai eu = =

Répondre

11

J'ai un sample implementation que vous pourriez regarder. Ce n'est pas conçu pour être efficace par tous les moyens, mais il devrait vous aider à démarrer.

Fondamentalement, un IOrderedEnumerable<T> a juste besoin d'avoir une idée de sa commande actuelle, de sorte qu'il peut en créer un nouveau. En supposant que vous avez déjà un IComparer<T> vous construisez un nouveau en disant quelque chose comme:

int Compare(T first, T second) 
{ 
    if (baseComparer != null) 
    { 
     int baseResult = baseComparer.Compare(first, second); 
     if (baseResult != 0) 
     { 
      return baseResult; 
     } 
    } 
    TKey firstKey = keySelector(first); 
    TKey secondKey = keySelector(second); 

    return comparer.Compare(firstKey, secondKey);   
} 

Donc, fondamentalement, vous créez une chaîne de allant de la comparateurs « moins important » jusqu'à la « plus importante ». Vous devez également mettre le « descendant » peu là-dedans, mais c'est facile :)

Dans l'échantillon lié ci-dessus, les trois aspects différents sont représentés dans trois classes différentes déjà présentes dans MiscUtil:

  • ReverseComparer : un revers résultats de » IComparer<T> existants
  • LinkedComparer: crée un comparateur de deux, avec un maître et un esclave
  • ProjectionComparer: crée un comparateur sur la base d'une projection des éléments d'origine à touches, à déléguer un autre comparateur pour comparer ces clés.

Les comparateurs sont parfaits pour enchaîner ensemble comme ceci.

+0

Sweet! Va le vérifier à la fois =) – Svish

+0

Donc, il se réorganiserait sur la base du nouveau comparateur que vous lui donnez? ou? Je ne sais pas si j'ai compris que ... – Svish

+0

Il ne serait pas réorganiser lui-même - il créerait une nouvelle séquence avec la nouvelle commande, basée sur l'ancien ordre et la nouvelle comparaison. Il n'utiliserait pas l'ancienne séquence sauf pour obtenir les données originales non ordonnées. Regardez le code pour plus de détails :) –

1

Vraisemblablement, votre classe aura une variable de stockage interne qui implémente IEnumerable (List<T> par exemple). La mise en œuvre de cette méthode est simple dans un tel cas:

private List<T> data = new List<T>(); 

public IOrderedEnumerable<CalculationResult> CreateOrderedEnumerable<TKey>(Func<CalculationResult, TKey> keySelector, IComparer<TKey> comparer, bool descending) 
{ 
    return descending ? 
     data.OrderByDescending(keySelector, comparer) 
    : data.OrderBy(keySelector, comparer); 
} 
+0

C'est faux. CreateOrderedEnumerable est appelée par la fonction LINQ "ThenBy" et doit conserver la commande déjà existante. L'utilisation de votre fragment pour implémenter CreateOrderedEnumerable remplacera l'ordre, ce qui entraînera la rupture de la sémantique de l'interface par votre implémentation. – Zarat

Questions connexes