Consider your behaviour and desires as a customer when you visit:

a) your favourite local coffee shop - you specify what you'd like, rather than how it's made. You care about the outcome, but rarely care about the process/sequences/steps that are followed as it's being constructed.
b) a Subway/Quiznos shop - you care equally about the outcome and the construction. Meats, veggies, bread type, order of placement of each, precise amount of mustard, pickles, etc.

baristaThe difference here is: you aren't instructing the coffee barista on how to steam the milk, or when to start brewing the espresso. You don't remind them that their level of ground beans is getting low, or where to store the milk. You are happy to assume they know their job best, and order of operations is properly under their control. They have their efficiencies to care about, and you're happy to let them manage that.

Consider now your desires as a programmer when your task is to find customers with a condition. Let's say we want to use this contrived example:

    Find the customers whose account balance owing is over $5,000. Find the youngest customer in that set. 
 

The Sandwich Model of Algorithms

//find all customers with the appropriate account balance
var owingOver5000 = new List<Customer>();
foreach (Customer c in myCustomers)
{
if (c.TotalAmountOwing > 5000)
{
owingOver5000.Add(c);
}
}

var youngestCust;
DateTime youngestBirthdate=null;

foreach(Customer c in owingOver5000)
{
//initialize on the first go-round; many ways to do this.
if (youngestBirthdate==null)
{
youngestBirthdate=c.BirthDate;
}

//find the youngest by their age
if (c.Birthdate < youngestBirthdate) //pretend nobody has the same birthdate ;)
{
youngestCust = c;
}
}
//you now have youngestCust populated (in most cases)


Very fine-grain operations are explicitly laid out by the developer, and execution path follows exactly what the developer wrote. Defects and all! The number of defects is up to you!

The Coffee Shop Model of Algorithms

Consider now the Coffee Shop model of this algorithm. We'll use LINQ.

var youngestCust = myCustomers
.Where(c=>c.TotalAmountOwing > 5000)
.OrderBy(c=>c.BirthDate)
.SingleOrDefault();

It should be obvious to you now, if it wasn't at the start: the LINQ extension methods are doing all the looping for you, and taking care of all the small bits and housekeeping. You, as the customer, don't want to care about how it's found, but rather, you declare what you want.

Outsource Your Loops

I hate to steal Eric Lippert's thought on this, but it's worth saying once more in a different way:

Avoid loops. They’re becoming a code smell. Let built-in methods and functionality do the boring non-value added logic for you.

You should be focused on YOUR business logic or end-goals (i.e. eating your sandwich and drinking your coffee), and less on syntax + language constructs. Take advantage of more declarative constructs provided in your language/framework. LINQ is a perfect example of this.

*this post is a mashup of Luca Bolognese's PDC 2008 F# metaphor and Eric Lippert's post on loops. Apologies to both!


Posted in: development , best practices , linq  Tags:
Actions: E-mail | Permalink | Comments (0) |
Phil posted on November 5, 2009 05:07

Perhaps you’ve got a collection of objects that you want ordered/sorted. I recently did. Perhaps you want them displayed in a non-deterministic manner or sorted randomly each time you write to an HTML view or otherwise consume that collection. Indeed, I did. (OK, lame shtick over…)

Randomize()

So imagine we’re working with a List of Customers.

data

Problem being, we don’t really have anything non-deterministic to work with. We could do this in SQL Server:

SELECT *
        ,(sin(Cust.ID * rand())) AS R
FROM Cust
ORDER BY R

This though, puts your presentation logic in your data tier. Maybe you don’t care, maybe it’s not a big price to pay. I wanted to take it up to the presentation tier and do this sorting right before binding or writing these objects to the page.

Taking the lead from Bruno Silva, I immediately realized this was the seed of the algorithm that I was looking for. Here’s my modification of Bruno’s algorithm:

   Random r = new Random(); 
   myCusts.OrderBy(x=>(r.Next())); //bind this, or use in a foreach

The call to r.Next() is obviously the key. Each object as it is evaluated in the OrderBy() will get a new random number associated with it. Celebrate good times!

Turn It Into an Extension Method

I haven’t written much here about how much I love extension methods in the .NET CLR 3.0. I can’t count the number of times that I’ve created a static ‘utility’ method that did something like this:

  • take in an object of some kind.
  • modify it.
  • return it back to the caller.
  • caller reassigns the return back into the object that it calls.

Rather than the above, I’ve created an extension method that I’ll be able to call whenever for any collection that implements IEnumerable. It’s trivial then to write the extension method for IQueryable.

ExtensionMethod I’ve submitted my Randomize() extension method over at ExtensionMethod.net. What a great site, by the way, kudos to those guys for taking user submissions and helping grow the use of this feature in .NET.

 

http://extensionmethod.net/Details.aspx?ID=236

public static IEnumerable<t> Randomize<t>(this IEnumerable<t> target)
   {
       Random r = new Random();
       return target.OrderBy(x=>(r.Next()));
   }


Posted in: development , c# , linq , extension methods  Tags:
Actions: E-mail | Permalink | Comments (0) |