2015-05-12 5 views
6

Ich habe derzeit Probleme, einen Weg zu finden, eine IOrderedEnumerable von einer SortedList zu erhalten.Convert SortedList in IOrderedEnumerable

Ich habe einen komplexen Typ, wir werden es jetzt nur 'A' nennen, das kann in eine Aufzählung vom Typ 'A' zerlegt werden. Ich bin derzeit einen SortedList in einer rekursiven Zerlegung Funktion schaffen, in dem der Schlüssel, ein int, auf die auftragsbezogene wird das Stück in zerlegt wurde: Jedoch

private static SortedList<int, A> RecursivelyBuildMySortedList(A myValue) 
{ 
    if (myValue == StopCondition()) 
    { 
     return new SortedList<int, A> { { 1, myValue } }; 
    } 

    var left = RecursivelyBuildMySortedList(myValue.Left); 
    var right = RecursivelyBuildMySortedList(myValue.Right).Select(entry => new KeyValuePair<int, A>(entry.Key + left.Count, entry.Value)).ToList(); 
    right.ForEach(pair => left.Add(pair.Key, pair.Value)); 
    return left; 
} 

, ich will nicht den SortedList für die Verbraucher belichten da der Wert des Schlüssels, der sich auf die Zerlegungsreihenfolge bezieht, für Verbraucher wenig Bedeutung hat (insbesondere als int). Das einzige, worüber sich ein Verbraucher kümmern muss, ist die endgültige Bestellung der Stücke, so dass jedes Stück in der richtigen Reihenfolge verarbeitet werden kann. Ich würde es vorziehen, den Verbrauchern ein IteredEnumerable zugänglich zu machen. Ich dachte, das eine ziemlich einfache Aufgabe sein würde, da ein SortedList in vielerlei Hinsicht sehr ähnlich einen OrderedEnumerable ist, aber ich habe noch nicht eine gute Umwandlung finden kann:

public static IOrderedEnumerable<A> Decompose(A myValue) 
{ 
    SortedList<int, A> mySortedList = RecursivelyBuildMySortedList(myValue); 

    // Can't find a way to preserve the order of the objects during 'OrderBy' 
    // mySortedList.Select(keyValuePair => keyValuePair.Value).OrderBy(obj => obj.index); 

    // The select statement would not match the return type that promises IOrderedEnumerable 
    // mySortedList.OrderBy(keyValuePair => keyValuePair.Key).Select(keyValuePair => keyValuePair.Value); 

} 

Hat jemand ein Verfahren zum Extrahieren ein IOrderedEnumerable von einer SortedList zum Verbrauch? Als Randbemerkung, ich bin mir dessen bewusst, dass:

return mySortedList.Select(keyValuePair => keyValuePair.Value); 

Würde ein IEnumerable zurückgeben, um ‚unter der Haube‘, aber wegen, wie wichtig die Reihenfolge, in der die zählbare ist verarbeitet bewahren würde, würde ich lieber Der Rückgabetyp muss beschreibend genug sein, um zu belegen, dass die zugrunde liegende Sammlung geordnet ist (um die API lesbarer zu machen).

+1

Warum muss _have_ zu einem 'IOrderedEnumerable <>' umgewandelt werden? Es sollte wirklich keine Notwendigkeit geben. Sie wissen 'SortedList <,>' ist sortiert ... –

+0

Ich denke, Sie sollten mit 'IEnumerable' gehen und fügen Sie einen Kommentar zu der Funktion, wie das Ergebnis sortiert ist. Die Rückgabe von "IOrderedEnumerable" sagt dem Kunden nicht wirklich etwas darüber, wie die Sammlungen sowieso geordnet sind. – Magnus

+0

@JeffMercado, weil das Offenlegen des Schlüssels, der zum Sortieren der Elemente verwendet wurde, für die Verbraucher bedeutungslos ist und ich hoffe, meine Präsentation des Ergebnisses zu bereinigen. Um die Frage anders zu formulieren, wenn 'Zerlegen' eine Funktion war, die eine ganze Zahl faktorisierte und die Faktoren in der Reihenfolge zurückgab, in der sie entdeckt wurden, der resultierende 'Schlüssel' in der sortierten Liste (die Reihenfolge, in der der Faktor entdeckt wurde) , wäre sinnlos, sobald das Ergebnis erhalten wurde. – LiamK

Antwort

2

Sie müssen die Werte propery der SortedList verwenden:

private IOrderedEnumerable<string> GetResults() { 
    SortedList<int, string> list = new SortedList<int, string>(); 
    list.Add(40, "Mehrzad"); 
    list.Add(20, "Chehraz"); 
    return list.Values.OrderBy(key => 0);   
    } 

Und dann verwenden:

IOrderedEnumerable<string> enumerable = GetResults(); 
foreach (var item in enumerable) { 
    System.Diagnostics.Debug.WriteLine(item); 
} 

Es seit SortiertNach arbeitet (key => 0) gibt Werte in ihrer ursprünglichen Reihenfolge der sind nach SortedList sortiert.

Oder Sie können IOrderedEnumerable (Meine alte Antwort) implementieren:

class OrderedEnumerableWithoutKey<TKey, TValue> : IOrderedEnumerable<TValue> { 
    private IOrderedEnumerable<KeyValuePair<TKey, TValue>> inner; 
    public OrderedEnumerableWithoutKey(IOrderedEnumerable<KeyValuePair<TKey, TValue>> inner) { 
     this.inner = inner; 
    } 
    public IOrderedEnumerable<TValue> CreateOrderedEnumerable<TKey1>(Func<TValue, TKey1> keySelector, IComparer<TKey1> comparer, bool descending) { 
     throw new NotImplementedException(); 
    } 
    public IEnumerator<TValue> GetEnumerator() { 
     return new Enumerator(inner.GetEnumerator()); 
    } 
    IEnumerator IEnumerable.GetEnumerator() { 
     return new Enumerator(inner.GetEnumerator()); 
    } 
    class Enumerator : IEnumerator<TValue> { 
     private IEnumerator<KeyValuePair<TKey, TValue>> inner; 
     public Enumerator(IEnumerator<KeyValuePair<TKey, TValue>> inner) { 
      this.inner = inner; 
     } 
     public TValue Current { 
      get { 
       return inner.Current.Value; 
      } 
     } 
     object IEnumerator.Current { 
      get { 
       return inner.Current.Value; 
      } 
     } 
     public void Dispose() { 
      this.inner.Dispose(); 
     } 
     public bool MoveNext() { 
      return this.inner.MoveNext(); 
     } 
     public void Reset() { 
      this.inner.Reset(); 
     } 
    } 
    } 

es dann in dieser Art und Weise verwenden:

private IOrderedEnumerable<string> GetResults() { 
    SortedList<int, string> list = new SortedList<int, string>(); 
    list.Add(20, "Mehrzad"); 
    list.Add(10, "Chehraz"); 
    return new OrderedEnumerableWithoutKey<int, string>(list.OrderBy(item => item.Key)); } 
.. 
.. 
// Consumer part: 
IOrderedEnumerable<string> enumerable = GetResults(); 
foreach (var item in enumerable) { 
     System.Diagnostics.Debug.WriteLine(item); 
} 
// Outputs: 
// Cherhaz 
// Mehrzad 
+0

Ihr 'OrderedEnumerableWithoutKey' explodiert, wenn' GetResults(). ThenB (..) 'aufgerufen wird. Es ist keine intuitive Sache für genannt. Und 'list.Values.OrderBy (key => 0)' sortiert die Liste, die bereits bestellt wurde. Es ist kein Problem an sich; aber könnte ineffizient sein, wenn die sortierte Liste riesig ist. –

+0

@SriramSakthivel Ich stimme zu, dass meine Antworten möglicherweise nicht die besten sind, und ich werde diese entfernen, wenn eine bessere Antwort gefunden wurde. –

+0

Ich hoffe meine ist besser: p –

2

Es gibt keine öffentliche Umsetzung IOrderedEnumerable zur Verfügung. Sie müssen selbst rollen.

Es ist ziemlich einfach mit Hilfe von Enumerable.OrderBy und Enumerable.OrderByDescending zu tun. Mit minimalem möglichen Code, sehen Sie die Implementierung unten.

public class SortedListOrderedEnumerable<TKey, TValue> : IOrderedEnumerable<TValue> 
{ 
    private readonly SortedList<TKey, TValue> innerList; 
    public SortedListOrderedEnumerable(SortedList<TKey, TValue> innerList) 
    { 
     this.innerList = innerList; 
    } 

    public IOrderedEnumerable<TValue> CreateOrderedEnumerable<TKey1>(Func<TValue, TKey1> keySelector, IComparer<TKey1> comparer, bool @descending) 
    { 
     return @descending 
      ? innerList.Values.OrderByDescending(keySelector, comparer) 
      : innerList.Values.OrderBy(keySelector, comparer); 
    } 

    public IEnumerator<TValue> GetEnumerator() 
    { 
     return innerList.Values.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

public static class Ext 
{ 
    public static IOrderedEnumerable<TValue> AsOrderedEnumerable<TKey, TValue>(
     this SortedList<TKey, TValue> list) 
    { 
     return new SortedListOrderedEnumerable<TKey, TValue>(list); 
    } 
} 

verwenden sie dann als

SortedList<int, string> list = new SortedList<int, string>(); 
... 
var ordered = list.AsOrderedEnumerable() 
    .ThenBy(...) 
    .ThenByDescending(...); 

Jetzt ist Ihre Decompose Methode

public static IOrderedEnumerable<A> Decompose(A myValue) 
{ 
    SortedList<int, A> mySortedList = RecursivelyBuildMySortedList(myValue);   
    return mySortedList.AsOrderedEnumerable(); 
} 

bearbeiten werden wird: Aktualisiert meine erste Antwort IOrderedEnumerable<TValue>, in Original Antwort zurück, es war IOrderedEnumerable<KeyValuePair<TKey,TValue>>

+0

Saubere Implementierung. @MehrzadChehraz konnte eine Antwort geben, bei der ich keine eigene Schnittstelle implementieren musste, aber das war auch geeignet. – LiamK

+0

@LiamK Ja. Aber das ist ineffizient, da es eine Liste bestellt, die bereits bestellt ist. Für kleine Listen ist das in Ordnung; Wenn die Liste riesig ist, ist es nicht. Abhängig davon können Sie sich entscheiden, es zu verwenden. –

+0

Messepunkt. Ich ging mit der anderen Antwort, weil das resultierende Aufzählungszeichen immer nur zwischen 1 und 3 Elemente enthalten wird. – LiamK

1

Sie möchten wahrscheinlich nichtverwendendafür.

IOrderedEnumerable existiert nur für Dinge wie ThenBy(...), wo Sie dynamisch die Sortierreihenfolge zur Laufzeit angeben (wirklich, nur einen Vergleich zu bauen).

SortedList auf der anderen Seite hat eine konstante Sortierreihenfolge und Vergleich - seine Reihenfolge kann nicht ändern.

Ich schlage vor, IEnumerable beizubehalten, es sei denn, Sie haben einen guten Grund, den Sie noch nicht angegeben haben. Denken Sie daran, dass Schnittstellen nicht dazu da sind, einen Typ zu dokumentieren (d. H., Indem Sie sagen "das ist geordnet"). Sie sind da, um die Funktionalität aufzudecken.