A perfect blend of all things Dot Net
I am really getting into LINQ now! I think it’s fantastic. I recently wanted to develop a quick drop-down list in ASP.Net which allows a user to select a time of day from a list. The times are 15 minutes apart, so the list would look like this:
…
08:00
08:15
08:30
08:45
09:00
…
… and so on.
Before LINQ, I would have done this with a for loop, like this:
List<string> times = new List<string>(); for (int hour = 0; hour < 24; hour++) for (int minute = 0; minute < 60; minute++) if (minute % 15 == 0) times.Add(string.Format( “{0:00}:{1:00}”, hour, minute));
That’s not difficult, although it’s not so easy to understand. I would have to write a small console app or test to make sure I had done it correct though.
I thought this might be a good opportunity to use LinqPad. It’s a great tool. You can use it to test a LINQ statement in a live window, so I thought I’d give it a go.
First I needed a LINQ statement to test.
The first thing I needed was an integer for the hour. That’s quite easy, especially if you use the Range Extension Method technique as I wrote about before. That method allows you to create an IEnumerable<int> from a simple statement, like 1.To(10). So to get the hours of the day, I can simply start with:
from hour in 0.To(23)
Now I need to do a cross-join with the minutes. In C# comprehension syntax, you do that by simply adding another from statement. At first, I thought I could do it by using an enumeration of minutes, specifying each value I wanted specifically. To do that I wrote this:
from hour in 0.To(23) from minute in new[] {0, 15, 30, 45}
That works very nicely. I think it’s easy to understand too. Even if you were going to come back to it years from now, you could still easily see what is being done.
Another alternative is to do the same as the for statement above, go through the numbers 0 to 59, selecting only those which are divisible by 15. You would do that using another range and a filter:
from hour in 0.To(23) from minute in 0.To(59) where minute % 15 == 0
Again, I like the way this looks. Another developer should have no difficulty reading that.
To select the string, we will also use the same format as before, this time using the select keyword:
select string.Format(“{0:00}:{1:00}”, hour, minute)
You then simply assign the value of this statement to a variable, like this:
var times = from hour in 0.To(23) from minute in 0.To(59) where minute % 15 == 0 select string.Format(“{0:00}:{1:00}”, hour, minute);
Now, if you haven’t already, go download LinqPad from here, and open it up. You will see a window to write a statement in the top right.
Before you continue, you need to add the extension methods to use my “To()” method. As a treat, just for you, here’s a simple assembly and a code file you can use straight away. Download it, save the binary dll somewhere, then do the following in LinqPad:
Now, put your cursor in the Query1 tab, and paste in the following:
from hour in 0.To(23) from minute in 0.To(59) where minute % 15 == 0 select string.Format(“{0:00}:{1:00}”, hour, minute)
Press F5, and you will see a generated list like this:
And that’s it! You can now see exactly what you will get when you run this code.
What do you think? I’d love to hear your comments.
Frank Quednau
January 19th, 2008 at 11:28 pm
Very nice, methinks. There is massive potential in this technology, both in dealing with collections (it’s becoming so concise) and dealing with mapping to domains beyond .NET objects. Apart from LINQ your “To” extension method inspired me to revisit my alphabet range object. Cheers!
Revisiting the Alphabet Range with the latest .NET - Frank-Leonardo Quednau
January 20th, 2008 at 12:09 am
[…] Richard Bushnell was showing off how old problems can be implemented very concise with LINQ he also made use of an extension method to the int […]
anonymous
January 20th, 2008 at 2:16 am
I like this, but I think it would be better to use a variation of To that has a step parameter like this:
from minute in 0.To(59, 15)
It’s much better perf-wise etc.