Thursday, November 29, 2007

Coding with Crayons

A while back I listened to a great interview of Neal Ford speaking on DSL's. In this interview Mr. Ford states that he
"Would rather code Groovy in Vi than Java in IDEA"

At first when I heard this, it brought me pause, but I quickly deemed it not worthy of any additional thought. That is until recently, when I was forced to write a small, trivial application in Java...with pen and paper. The problem is stated below, and it had to compile and run. If I had my trusty IDE with intellisence, code completion, syntax highlighting, and refactoring I could have probably cranked out the solution in about a minute (it actually took me about 4 minutes when I tried, but there were unit tests involved).

As a counterpoint I decided to solve the same problem in Groovy. To do the Groovy development I fired up TextMate on my Mac (but I could have just as easily used the ever crappy Notepad on Windows).

What I came away from this exercise: How relient I had become on my IDE to make me an efficient and effective Java developer. Java is just to verbose and rigid of a language to code in pen and paper, even for a simple app. With Groovy I feel like I could break out the box of 64 Crayola Crayons and happily code away on some construction paper, run it through an OCR scanner and then execute it via the command line. Joy!

It also got me thinking of Mr. Fords original quote and I now appreciate what a profound statement that really was.

PROBLEM:
  • You have a List of letters (A-G)
  • Create a class and the necessary methods that do the following:
    • In the list replace:
      • B with C
      • D with X
      • X with Z
  • The replacement should handle all transitive replacements
  • All duplicates in the list should be removed.
My Java Solution:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class ListSwapper {


public static void main(String[] args) {
ListSwapper swapper = new ListSwapper();

List baseList = new ArrayList() {
{
add("A"); add("B"); add("C"); add("D");
add("E"); add("F"); add("G");
}
};

List dedupedList = new ArrayList() {
{
add("A"); add("C"); add("Z");
add("E"); add("F"); add("G");
}
};

List result = swapper.dedupe(swapper.swap(baseList));

assert result.equals(dedupedList);
}

private Map map = new HashMap(){
{
put("B", "C"); put("D", "X"); put("X", "Z");
}
};

List swappedList = new ArrayList();

public List swap(List baseList) {
for (Iterator iterator = baseList.iterator(); iterator.hasNext();) {
String letter = (String) iterator.next();
swapLetter(letter);
}
return swappedList;
}


private void swapLetter(String letter) {
String swappedLetter = map.get(letter);
if (swappedLetter == null) {
swappedList.add(letter);
} else if (swappedLetter != null) {
swapLetter(swappedLetter);
}
}

public List dedupe(List swappedList) {
for (int i = 0; i < j =" i">



My Groovy Solution (This is a method-to-method replacement)


class Util {
def myMap = ['B':'C' , 'D':'X', 'X':'Z']

def swap(List list){
list.eachWithIndex {item, index ->
list[index] = swap(item)
}
list
}

def swap(letter){
def newLetter = myMap.get(letter)
newLetter ? swap(newLetter) : letter
}

def prune(list){
list.unique()
}
}

def x = new Util()
assert x.prune(x.swap(('A'..'G').toList())) == ["A", "C", "Z", "E", "F", "G"]

This code could probably be made Groovier. The prune(list) method seems a little unnecessary at this point.

1 comment:

Anonymous said...

These puzzles are fun :), how about:

def swapMap = ['B':'C', 'D':'X', 'X':'Z']

assert ('A'..'G').collect{ while (swapMap[it]) { it = swapMap[it] }; it;}.unique() == ["A", "C", "Z", "E", "F", "G"]