Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 412
Jonathan Avatar asked Mar 24 '11 07:03

Jonathan


2 Answers

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.)

like image 170
Jon Skeet Avatar answered Sep 17 '22 17:09

Jon Skeet


Not a direct answer to your question (sorry!) - more a question on the question:

  • Do you actually need the output to be a SortedList?
  • Or can you survive with the output being an IEnumerable where the results happen to be in the right order?

If you never intend to add/insert more items to mostDays collection after you've created it, then you could obviously just create an IEnumerable using var mostDays = allDays.Where(n => n.Value.IsRequested || n.Value.IsApproved);

like image 39
Stuart Avatar answered Sep 21 '22 17:09

Stuart