Saturday, January 30, 2016

Optional get Method on a Java Map

Lately I've been doing both Java 8 (for work) and Scala (for fun and personal development). And although I like Java 8's functional features, they're naturally lacking compared to Scala.

One thing specifically that I wanted this week was a java.util.Optional-returning get() method on a Map. (I was dealing with nested maps at the time.) This method is something that clearly ought to exist but doesn't, probably because it would be too hard to engineer into the Map interface in any kind of backward-compatible way.

So I started a playground in my Github blog code repository for Functional Java and took a crack at building something to address this. What I came up with was a Map wrapper classed that I called "FuncMap". Its banner (and currently, only) feature is a new method called "getOption" that takes a key and returns an Optional-wrapped value:

  public Optional getOption(K key) {
    return Optional.ofNullable(get(key));

  }

That's all it takes to enable a Nullable-free programming style on the Map interface. The following three test cases demonstrate how this works with flatMap.
  @Test
  public void testNestedMapsFirstGetIsNull() {
    FuncMap<String, FuncMap<String, String>> nestedMap =
        new FuncMap<>(new HashMap<String, FuncMap<String, String>>());
    
    String result = nestedMap.getOption("user")
        .flatMap(x -> x.getOption("scott"))
        .orElse("UNKNOWN");
    assertEquals("UNKNOWN", result);
  }

  @Test
  public void testNestedMapsSecondGetIsNull() {
    FuncMap<String, FuncMap<String, String>> nestedMap =
        new FuncMap<>(new HashMap<String, FuncMap<String, String>>());
    nestedMap.put("user", new FuncMap<>(new HashMap<>()));
    
    String result = nestedMap.getOption("user")
        .flatMap(x -> x.getOption("scott"))
        .orElse("UNKNOWN");
    assertEquals("UNKNOWN", result);
  }

  @Test
  public void testNestedMapsWholeExpressionNotNull() {
    FuncMap<String, FuncMap<String, String>> nestedMap =
        new FuncMap<>(new HashMap<String, FuncMap<String, String>>());
    nestedMap.put("user", new FuncMap<>(new HashMap<>()));
    nestedMap.get("user").put("scott", "admin");
    
    String result = nestedMap.getOption("user")
        .flatMap(x -> x.getOption("scott"))
        .orElse("UNKNOWN");
    assertEquals("admin", result);
  }
Yeah, still a little clunky compared to Scala. But it's progress, right?

Tuesday, January 19, 2016

Simulating the "Can't Stop" Dice Game Using Scala

The board game "Can't Stop" has captivated my family since I was a kid. Over the past year, we've been playing a lot. But I often find myself on the losing end to my fiancee, who is a very tough board gamer.

At its core, "Can't Stop" is a probability game. As such, I'm sure a precise probabilistic analysis of the best playing approach is possible. But coming up with a basic strategy is a problem best solved with simulation.

So I wrote some Scala code to do some Monte-Carlo-style simulations to answer the following question: For each triple of numbers on the "Can't Stop" board, what is the average number of times I can roll the dice without losing my turn?

The answer for the ever-popular 6-7-8 combination over 10,000 trials comes out to around 11.5 rolls. On the other hand, the most difficult possible combinations of 2-3-12 and 2-11-12 only allow you to roll about 0.75 times. (In other words, if you find yourself on those numbers, you should most likely quit rolling immediately.)

Although I think this could be a step in the direction of writing a decent AI for the game, as it stands, it's not very usable. When I tried playing some real human games rolling the "recommended" number of times, I lost consistently and badly. That's because in a real game, going out on half your rolls is far too frequent. Perhaps if I re-ran the simulation looking for, say, an 80% success rate instead of 50% (at least for the "easier" combinations), I could come up with a playable table of roll counts.

The implementation is quite straightforward, largely thanks to Scala and List's combinations() method. Iterating over all of the triples from 2 to 12 can be set up in a for loop like this:

val numbers = for (i <- 2 to 12) yield i
for (markers <- numbers.combinations(3)) {
  // ...
}

Clean and simple.

Sunday, January 10, 2016

Processing CSV Files in Java -- A Java 8 Perspective

Well, after a couple of years' hiatus, I'm going to try and start blogging here again. I'm going to do some things differently going forward. First, I'm going to moderate comments, since Blogger allows too much spam to get through. Second, instead of jumping through hoops trying to squeeze a bunch of properly formatted code into Blogger, I'm going to keep the bulk of the code in a Github repository I set up expressly for this purpose. You can find it here -- https://github.com/scottmcmaster/blogcode.

For today's post, I'm going to tackle the common task of processing CSV files. My fiancee recently spent a lot of time writing one-off CSV parsers for her work, where she had to read in a file, make a few conditional changes to some values, and write the modifications back out. The canonical way of processing a CSV file without any higher-level assistance goes something like this:
  1. Read a line of the input file.
  2. Split it.
  3. Change one value in the line.
  4. Change another value in the line, then another, until complete.
  5. Write the line back out.
  6. Repeat.
With tools like Apache Commons CSV and openCSV, one can easily do a bit better in terms of conciseness, readability, and robustness.

But after watching my fiancee's specific issues, what I really wanted to be able to do was process columns of values instead of rows. Something like this:
  1. Read the entire input file to an in-memory data structure.
  2. Change all of the values in one column.
  3. Change the values in another column, etc. until complete.
  4. Write the file back out.
(Granted, this requires reading the entire file into memory, but for many applications, this is not an issue.)

My intuition was that column-oriented processing would make the business logic clearer and less error-prone in the code. To further this goal, I wanted to be able to do this with Java 8 syntax, closures and the like.

My proof-of-concept code is available here. It uses Apache Commons CSV to read input into a data structure, the "CSVMaster". It contains a list of rows whose values are mapped by the column headers for easy access. Many CSV frameworks support that. What's slightly new is how the row list's iterator and stream are exposed. So you can write code like this:

// Change each zip value to a default zip+4.
master.forEach(row -> row.set("zip", row.get("zip") + " -0000"));

// Get all of the rows from a specific zip code.
List specialRows = master.stream().filter(row -> row.get("zip").startsWith("95610"))
    .collect(Collectors.toList());

Provided this turns out to be useful and usable, I will continue to enhance and extend it. Additional thoughts welcome.