Wednesday, April 25, 2012

Short and Sweet

So today at work I had to come up with a method that would give me a listing of something from a collection. If the listing didn't exist, I wanted the listing to be initialized and automatically added to the list.

Let's look at my pathetic first attempt.


private Listing GetListing(List<Listing> cars, string name)
{
    Listing listing = null;
    IEnumerable<Listing> results = cars.Where(i => i.Name == name);

    //if map doesn't exist create it
    if (results.Count() == 0)
    {
        listing = new Listing()
        {
            Name = name,
            AdditionalData = new List<Data>()
        };

        cars.Add(listing);
     }
     else
     {
         //If we originally did this, it would throw an 
         //exception when there are no matches found. 
         //That's why this part is in the else block.
         listing = results.First();
     }

     return listing;
}

As you can see, I tried to get fancy and use Linq. I found, through testing, that the method .First() would throw an exception if there were no results. There were other methods, but for some reason I just couldn't think of the right method.

So then I threw my hands in the air and figured it'd be shorter to just write a method without Linq and that I was just over complicating it.



private Listing GetListing(List<Listing> cars, string name)
{
    Listing listing = null;

    for (int i = 0; i < cars.Count; i++)
    {
        if (cars[i].Name == name)
            listing = cars[i];
    }

    if(listing == null)
    {
        listing = new Listing()
        {
            Name = name,
            AdditionalData = new List<Data>()
        };

        cars.Add(indexMap);
    }

    return listing;
}

Oddly this looked exactly the same. I was thinking to myself, there just has to be a better way. Isn't there some kind of flag I can pass to Linq so that I can just get a null result. It made me look at .First() again, when I saw .FirstOrDefault() Then I realized, that was the method I was looking for.

For those who don't know, .FirstOrDefault() will return either the first element or the default value. If it's an object, that means it'll come back null. A quick test to prove this...


public class Program
{
    public static void Main(string[] args)
    {
        Data[] values = new Data[] 
        {
            new Data(){Value = "one"},
            new Data(){Value = "two"},
            new Data(){Value = "three"}
        };

        Data first = values.FirstOrDefault(i => i.Value == "ten");

        if (first != null)
            Console.WriteLine(first.Value);

        Console.ReadLine();
    }
}

public class Data
{
    public string Value { get; set; }
}

The above program results in nothing being written to the console. The moment you change the value being searched to one, two or three. It will output the value. This means I could now quickly refactor my method to now look like the following.


private Listing GetIndexMapping(List<Listing> cars, string name)
{
    Listing listing = cars.FirstOrDefault(i => i.Name == name);

    if (listing == null)
        cars.Add(listing = new Listing(name));

    return listing;
}

Much cleaner, although I still haven't made up my mind on if I should initialize and add the data to the collection at the same time. It's short and simple enough that it shouldn't be a problem. I'm going to have to start taking a closer look at the Linq API from now on. Especially now that I found out about the programmer competency matrix.

References:
Linq Method
Competency Matrix

No comments:

Post a Comment