Search code examples
c#linqfiltersortedlist

C# Linq SortedList Filtering into SortedList


I have got some code in which I am doing some weirdness to get information out of a SortedList and back into another SortedList. I do my where clause, then have to individually put all the KeyValuePairs back into a new SortedList.

This can't be the most efficient, or indeed the recommended, way of doing this, but I can't seem to find a better way.

Here is the code:

SortedList<DateTime, CalendarDay> most_days = 
                                new SortedList<DateTime, CalendarDay>();
List<KeyValuePair<DateTime, CalendarDay>> days = this.all_days.Where (
                                  n => n.Value.IsRequested || n.Value.IsApproved
                                  ).ToList();
foreach (KeyValuePair<DateTime, CalendarDay> kvp in days)
    most_days.Add(kvp.Key, kvp.Value);

Any ideas on how I can clean this up (less is more, as they say)?

Thanks,

Jonathan


Solution

  • Well you could certainly remove the ToList call - that's not helping you at all.

    You could make the calling code simpler like this:

    var dictionary = allDays.Where(n => n.Value.IsRequested || n.Value.IsApproved)
                            .ToDictionary(x => x.Key, x => x.Value);
    var mostDays = new SortedList<DateTime, CalendarDay>(dictionary);
    

    ... but that's going to build an intermediate Dictionary<,>, so it's hardly efficient.

    Another option is that you could write your own ToSortedList extension method, e.g.

    public static SortedList<TKey, TValue> ToSortedList<TSource, TKey, TValue>
        (this IEnumerable<TSource> source,
         Func<TSource, TKey> keySelector,
         Func<TSource, TValue> valueSelector)
    {
        // TODO: Argument validation
        var ret = new SortedList<TKey, TValue>();
        foreach (var element in source)
        {
            ret.Add(keySelector(element), valueSelector(element));
        }
        return ret;
    }
    

    Then the calling code will just be:

    var mostDays = allDays.Where(n => n.Value.IsRequested || n.Value.IsApproved)
                          .ToSortedList(x => x.Key, x => x.Value);
    

    I suspect this should be reasonably efficient, as it will always be adding values to the end of the list during construction.

    (For a complete job you'd want to add overloads accepting custom key comparers etc... see ToDictionary.)