11

I am binding a combobox using enumerable.range() and it works fine. Now I am trying to display the results in descending order, how can I do that?

  cboYearList.ItemsSource = Enumerable.Range( DateTime.Today.Year,1950).ToList().OrderByDescending();
Mathemats
  • 1,185
  • 4
  • 22
  • 35

2 Answers2

22

You can Reverse the list after creating it with Enumerable.Range:

cboYearList.ItemsSource = Enumerable.Range(DateTime.Today.Year, 1950).Reverse().ToList();

Or if you want to keep your OrderByDescending, you need to pass a key selector (the i => i at the end):

cboYearList.ItemsSource = Enumerable.Range( DateTime.Today.Year,1950).OrderByDescending(i => i).ToList();
Pierre-Luc Pineault
  • 8,993
  • 6
  • 40
  • 55
  • thanks for the support: ` int numberOfyears = DateTime.Now.Year - 1900; cboYearList.ItemsSource = Enumerable.Range(1900, numberOfyears).Reverse().ToList(); ` –  Mar 02 '15 at 04:11
  • 4
    The default implementation of `Reverse()` uses an intermediate buffer which may result in suboptimal memory usage. – Dai Feb 09 '19 at 22:25
1

I wrote an extension method that can be applied on a ValueTuple<int,int>, and is in my opinion the easiest way to use, if your language version already supports them. In your example that would be used like this:

cboYearList.ItemsSource = (DateTime.Today.Year, 1950).EnumerateInclusive().ToList();
cboYearList.ItemsSource = (1950, DateTime.Today.Year).EnumerateInclusive().ToList(); //reverse

I implemented the extension method like this. Just put it in a static class in your namespace.

/// <summary>
/// Enumerates all values between the first and second value in range. 
/// Automatically handles the enumeration-direction.
/// </summary>
/// <param name="range">The first parameter specifies the first value of the enumeration, 
/// the second parameter specifies the last value of the enumeration.</param>
public static IEnumerable<int> EnumerateInclusive(this (int start, int end) range)
{
    if (range.start <= range.end)
        for (int i = range.start; i <= range.end; i++)
            yield return i;
    else
        for (int i = range.start; i >= range.end; i--)
            yield return i;
}

The name is chosen that it is clear that both, start and end, are included in the enumeration. It has the advantage to support iteration in both directions in contrast to Enumerable.Range which only iterates ascending. In case you need to target an older Language Version you could easily do without ValueTuples, but I like this short and concise way without having to remember a class name.

azt
  • 2,100
  • 16
  • 25
  • 1
    Nice extension, though, it doesn't work right. Reversed for loop should be `for (int i = range.start; i >= range.end; i--)` – Denis Dec 05 '21 at 09:54
  • Thanks @Denis, I fixed it above. The original was `for (int i = range.end; i >= range.start; i--)` in Line 13. – azt Dec 10 '21 at 09:01