Refactoring To Functional Code

In my previous post I explained that some problems are better suited to a functional approach than traditional, imperative code. I showed an example of a problem that suits a functional approach and demonstrated turning several lines of imperative code with nested for-each loops and if-statements into a single line of functional code. Paul Harrington posted a comment asking what individual steps I took to refactor the code. Here’s my explanation of the refactoring:

First, here is the original, imperative method.

public int[] Translate(string word)
    ArrayList numbers = new ArrayList();

    foreach (char character in word)
        foreach(KeyValuePair<int, char[]> key in keys)
            foreach(char c in key.Value)
                if(c == character)

    return (int[]) numbers.ToArray(typeof (int));

As you can see, it takes some effort to determine what’s really going on. From this code we can determine that:

For each character in a word, select the first key in the list of keys that contains the character and add it to an array of numbers to return.

Now, lets express the statement above as functional code:

To select each character in a word, we need to convert the string to an array of characters. The LINQ Select method projects each element of a sequence into a new form. In this case, a string translates to a sequence of characters:

IEnumerable<char> characters = word.Select(c => c);

For each character, we need to find the corresponding key that contains the character. The First method returns the first element of a sequence:

int key = keys.First().Key;

In our case we need the first key in the list of keys that contains the character. The First method has an overload that returns the first element in a sequence that satisfies a specified condition.  To specify our condition we use the Contains method, which determines whether a sequence contains a specified element:

char c = 'a';
int number = keys.First(k => k.Value.Contains(c)).Key;

When we combine the code that selects each character with the code that gets the first key containing the character, we end up with this:

IEnumerable<int> numbers = word.Select(c =>
        keys.First(k => k.Value.Contains(c)).Key);

Finally, we use the ToArray method to return an array of type int. Now we have our final, refactored method:

public int[] Translate(string word)
    return word.Select(c =>
        keys.First(k => k.Value.Contains(c)).Key).ToArray();

I hope this helps to explain the steps I took to refactor imperative code to functional code. You can get really clever with functional code, but remember, readability is what’s most important. Sometimes it’s best to stick with good old-fashioned for-loops and if-statements, but for some problems, like above, a functional approach can lead to more readable, clean and concise code.

About these ads

3 Responses to “Refactoring To Functional Code”

  1. 1 Paul Harrington April 14, 2010 at 9:38 am

    Thanks Tim,

    I know a lot of people who will appreciate this explanation and it will make it that little bit easier for them to move forward into the interesting world of functional programming!

  2. 2 Pavel April 17, 2011 at 10:37 pm

    Hi Tim,
    When I was looking at this line:
    foreach(KeyValuePair key in keys)
    I was thinking where the keys variable comes from. I looked a few times at the arguments list and at the beginning of the method, thinking that maybe I missed it there.
    Don’t you think it’s better to have a special naming convention for private members, so one could easily understand, looking at the code, that it’s a private member. Like maybe using a “_” prefix or prefixing it with “this”?

  3. 3 timross April 17, 2011 at 10:46 pm

    Hi Pavel, sorry yes this post was a continuation from a previous post: There you will find the keys Dictionary declared. You’re right, I could have probably make the code clearer by adding the underscore prefix to private members. I know many people have personal preferences for how to declare private members, but in the case it would help to improve readability. Thanks for the suggestion!

Leave a Reply

Please log in using one of these methods to post your comment: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Get every new post delivered to your Inbox.

%d bloggers like this: