Building things that matter

Code Challenges

Friend or Foe (Ruby)

It's Monday morning, so before getting into the day's projects, I decided to tackle a coding challenge.  This one was not difficult at all, however, as with other challenges, I took it to a more complex level.

The Challenge

Make a program that filters a list of strings and returns a list with only your friends name in it.
If a name has exactly 4 letters in it, you can be sure that it has to be a friend of yours! Otherwise, you can be sure he's not...

Ex: Input = ["Ryan", "Kieran", "Jason", "Yous"], Output = ["Ryan", "Yous"]
Note: keep the original order of the names in the output.

My Solution

As noted above, this challenge is pretty easy and can easily be solved with one or two lines of code that would look something like: 

def friend(friends) { |name| name.length == 4 }

My thoughts on this were that if we are sorting a list of names into friends and foes based on the length of their name, we can go a bit farther to account for future expansion of this program as well as granular control and views into each role and the objects associated with each role.  

First thing I did was change the way the method was written.  I kept the name of the method as friend, but I changed the parameter from "friends" to "names," since what we are given is a string of names that we need to determine if they are friends or not.  It's misleading, at least psychologically, to call that parameter 'friends' when it is actually an array of names we are sorting and some will not be friends when we are done.

There were three things we are looking to define for each of the names in the list, the name, to return, the name length, and the role that name will get based on its length.  This felt to me to be an object and that we would have a collection of these objects, either friend or foe, sorted after we take a look at their lengths.  

So I created two empty hashes to hold my friend objects and my foes objects.  This challenge didn't require we hold the foe names, they could just be trash collected, but in terms of preparing for expansion, I decided to hold on to the foes just in case we need it. 

From here I iterate over the list of names we are given as a parameter, I look at the length of each name and, based that I jump into one of two additional methods, one that will create my friend objects, and one that will create my foe objects. 

Create Friend Method

Create Foe Method

Each of these methods takes the name that is being analyzed, and either the friends_hash or foes_hash and creates an object inside its respective hash with the information we need from that name, the name itself, the length and the role that object will have.  The key for each of these objects is the name, while this works for this challenge, we would want to have a way to make sure these keys are unique in the event that we end up with two of the same names given to us as a parameter.

With some more work I could likely combine these methods into one, and add a conditional for defining the role for the individual object created, since the role is the only current difference between the friend and foe objects.  However, i do like having these as separate methods for visibility into what is happening and granular control of how each role is created. 

While two people names "Sean" would still be considered friends, we would want to distinguish between the two of them and we could not do that by using only their name as a key in our friends hash, thus why we use id's or UUIDS to identify objects in the real world. But I digress. 

This set up lets us be ready to put additional values on our objects as our program expands including other scoring parameters, statuses, etc. 

Finally, to return the result the challenge is looking for, we map over the hash of friends, and return the name for each value.  

That's about it.  Time to get into some real work now.  Cheers. 

Robert Cornell