Convert SortedList to IOrderedEnumerable

I am currently having trouble finding a way to get IOrderedEnumerable from a SortedList.

I have a complex type, we just call it "A" for now, which can be decomposed into an enumerated type "A". I am currently creating a SortedList in a recursive decomposition function, where the int key is associated with the order in which the fragment is decomposed:

 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; } 

However, I do not want to set SortedList for consumers, since the value of the key associated with the decomposition order has little value for consumers (especially as int ). The only thing the consumer should take care of is that the final order of the parts was such that each piece can be processed in the correct order. I would rather expose IOrderedEnumerable users. I thought it would be a fairly simple task, since the SortedList is very much like OrderedEnumerable in many ways, but so far it has not been able to find a good transform:

 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); } 

Does anyone have a method to extract an IOrderedEnumerable from a SortedList for consumption? As a remark, I know that:

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

I would return an IEnumerable that would preserve the order under the hood, but because of the importance of the order in which the enumerated is processed, I would prefer the return type to be descriptive enough to indicate that the base collection is ordered (to make API is more readable).

+6
source share
3 answers

You need to use the "Values" property in the SortedList:

  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); } 

And then use:

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

It works because OrderBy (key => 0) returns values ​​in the original order, which are sorted by SortedList.

Or you can implement IOrderedEnumerable (My old answer):

 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(); } } } 

Then use it like this:

 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 
+2
source

There is no public implementation of IOrderedEnumerable . You will have to collapse yourself.

This is pretty simple to do with Enumerable.OrderBy and Enumerable.OrderByDescending . With the smallest possible code, see the implementation below.

 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); } } 

Then use it like

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

Now your Decompose method will become

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

Edit: updated my original answer to return IOrderedEnumerable<TValue> , the original answer was IOrderedEnumerable<KeyValuePair<TKey,TValue>>

+2
source

You probably don't want to use IOrderedEnumerable for this.

IOrderedEnumerable exists exclusively for things like ThenBy(...) , where you dynamically specify the sort order at runtime (actually just build a comparator).

SortedList , on the other hand, has a constant sort and compare order β€” its order cannot be changed.

I suggest sticking with a simple IEnumerable unless you have a good reason that you haven't talked about yet. Remember that interfaces do not exist to document the type (i.e. Saying "this is ordered"). They can reveal functionality.

+1
source

Source: https://habr.com/ru/post/987085/


All Articles