Sunday, August 06, 2006

Pair Programming with Nic

This weekend I made the trip to Morris, MN to do some pair programming with UMM professor & friend Nic McPhee. The objective of the day was to help me on my path back to programming.

I knew I want to do a few things, 1. re-awaken my Java brain cells 2. learn Eclipse, and 3. get started on learning Ruby, anything else would be a blessing. Current UMM and Nic is in a unique to help me with all three. UMM uses Java as the main language for programming classes and most of the students are now using Eclipse (in my day we used Emacs and some used Vim). Luckily Nic is contemplating a switch to Ruby for the Intro to Computer Science class down the road, but more imediately for the Software Engineering course this fall for upper-division students. This change has required Nic to spend a good chunk of his summer learning Ruby, so I'm going to use that knowledge to get some Ruby exposure.

Nic and I worked on a problem that I see a lot at work, fiding the matches between two lists of users. Now for this venue I've changed the list of names to those who have a much lower expecation of privacy.


List 1:
Castillo, Louis
Morneau, Justin
Mauer, Joe
Cuddyer, Micheal
Hunter, Tori
Punto, Nick
White, Rondell
Ford, Lew
Stewart, Shannon
Kubel, Justin
Tyner, Justin
Liriano, Francisco
Santana, Johan
Silva, Carlos

List 2:
Mauer, Joe
Konerko, Paul
Thome, Jim
Cano, Robinson
Lopez, Jose
Glaus, Troy
Tejada, Miguel
Young, Michael
Dye, Jermaine
Matthews, Jr, Gary
Ordonez, Magglio
Ramirez, Manny
Rios, Alex
Sizemore, Grady
Liriano, Francisco
Rivera, Mariano
Ryan, B.J.
Santana, Johan
Zito, Barry

As you may have guessed I'm using players from the Twins roster and the 2006 AL All-Star roster.

Here is the Java code:

public class MySearchClass {

private List<String> mnTwins;
private List<String> allStars;

public static void main(String[] args) throws Exception {
MySearchClass searchClass = new MySearchClass();
searchClass.compareFiles(args);
}

private void compareFiles(String[] args) throws Exception {
mnTwins = openAndReadFile(args[0]);
allStars = openAndReadFile(args[1]);

Collections.sort(mnTwins);
Collections.sort(allStars);
int twinsIndex = 0;
int allStarIndex = 0;

while(hasEntries(twinsIndex, allStarIndex)){
String twinsPlayer = mnTwins.get(twinsIndex);
String allStarName = allStars.get(allStarIndex);
if(nameMatch(twinsIndex, allStarIndex)){
System.out.println(twinsPlayer + "\t"+ allStarName);
allStarIndex++;
} else if(twinsPlayer.compareTo(allStarName) < 0) {
twinsIndex++;
} else {
allStarIndex++;
}
}
}

private boolean nameMatch(int termedIndex, int activeIndex) {
return allStars.get(activeIndex).startsWith(mnTwins.get(termedIndex));
}

private boolean hasEntries(int twinsIndex, int allStarIndex) {
return twinsIndex < mnTwins.size() && allStarIndex < allStars.size();
}

private static List<String> openAndReadFile(String fileName) throws Exception {
FileReader fileReader = new FileReader(fileName);
BufferedReader bufferedReader = new BufferedReader(fileReader);

String line = bufferedReader.readLine();
List<String> names = new ArrayList<String>();
while(line != null){
names.add(line);
line = bufferedReader.readLine();
}
return names;
}
}


For some reason the List are typed properly they should be a String. Check out MySearchClass is written correctly and that it will compile.

Now here is the Ruby code we wrote afterwords:

class TwinsAllStars
attr :mnTwins
attr :allStarRoster

def read_names(file_name)
names = Array.new
File.open(file_name) do |file|
file.each_line { |line| names << line }
end
return names
end

def initialize
@mnTwins = read_names("mnTwins.txt").sort
@allStarRoster = read_names("allStarRosterList.txt").sort
end

def processFiles
puts @mnTwins & @allStarRoster
twinsIndex = 0
allStarIndex = 0
termedName = @mnTwins[twinsIndex]
allStarName = @allStarRoster[allStarIndex]

while hasEntries(twinsIndex, allStarIndex) do
if allStarName.match(/^#{termedName}.*/)
puts termedName + "\t" + allStarName
allStarIndex += 1
allStarName = @allStarRoster[allStarIndex]
elsif termedName < allStarName
twinsIndex += 1
termedName = @mnTwins[twinsIndex]
else
allStarIndex += 1
allStarName = @allStarRoster[allStarIndex]
end
end
end

def hasEntries(twinsIndex, allStarIndex)
twinsIndex < mnTwins.size and allStarIndex < allStarRoster.size
end
end

user_conflict = UserConflict.new

user_conflict.processFiles



Now as you can see it is nearly a duplicate of the way we solved the problem in the same way we solved it with Java. After some thought we looked at the problem again and realized we could do a better job with a different data structure, istead of Lists we would use Sets. Here is our new Ruby code:



def read_names(file_name)
names = Array.new
File.open(file_name) do |file|
file.each_line { |line| names << line }
end
return names
end

mnTwins = read_names("mnTwins.txt").sort
allStarRoster = read_names("allStarRosterList.txt").sort

puts mnTwins & allStarRoster


Ahh, now that looks right. A nice simple way to find the matches.

Please let me know if you have any comments and if we could have done it better.

2 Comments:

At 8/08/2006 12:53 AM, Anonymous Nic McPhee said...

I think the Java code got mangled. It looks like the parameterized types gotten mistaken for HTML tags and swallowed. As it appears (to us), I don't think it will work.

It was a great visit - thanks!

 
At 8/08/2006 7:28 AM, Blogger Dan Flies said...

Thanks Nic. It should all be fixed now.

 

Post a Comment

Links to this post:

Create a Link

<< Home