Sunday 21 December 2014

G'day:
Adam Presley is a bit of a star. I had a look at his original entry to the code puzzle and decided I didn't like it as it was too long-winded ("Weekend code puzzle: Adam Presley's answer (Go)"). He's subsequently come back to me with a simplified version, listed on his own blog: Response To Adam Cameron's Code Review. He took my comments in good grace, which is very good of him.

Let's have a look at this new version:

``````// getSubseries.go

package main

import (
"flag"
"fmt"
"os"
"strconv"
"strings"
)

type SubArrayResult struct {
Sequence []int
Total    int
}

var input = flag.String("input", "", "Comma delimited list of integer numbers")
var threshold = flag.Int("threshold", 10, "Integer number for array slice to not exceed")

func main() {
flag.Parse()

/*
* Array of integers to determine longest sequence from. These are a string
* list on the command line that are converted to integers.
*/
inputArray := make([]int, 0)

if *input == "" {
fmt.Println("Please provide a valid input of comma delimited integers")
os.Exit(1)
}

/*
* Get the input from the console args, and split them up
* into integers in an array
*/
for _, value := range strings.Split(*input, ",") {
i, err := strconv.Atoi(value)
if err != nil {
fmt.Println("ERROR - Unable to convert", value, "to integer")
os.Exit(1)
}

inputArray = append(inputArray, i)
}

/*
* Loop, slice, sum
*/
sequences := make([]SubArrayResult, 0)

for index, _ := range inputArray {
sequence := make([]int, 0)
total := 0

inputSlice := inputArray[index:]

for _, value := range inputSlice {
if (total + value) <= *threshold {
total += value
sequence = append(sequence, value)
} else {
break
}
}

if len(sequence) > 0 {
result := SubArrayResult{
sequence,
total,
}

sequences = append(sequences, result)
}
}

/*
* Who wins?
*/
longestIndex := 0
longestLength := 0

for index, item := range sequences {
if len(item.Sequence) > longestLength {
longestLength = len(item.Sequence)
longestIndex = index
}

if len(item.Sequence) == longestLength && item.Total > sequences[longestIndex].Total {
longestLength = len(item.Sequence)
longestIndex = index
}
}

if len(sequences) > 0 {
winningSequence := sequences[longestIndex]

fmt.Println("")
fmt.Println("Sequence", winningSequence.Sequence, "wins with a length of", len(winningSequence.Sequence), " for a total of", winningSequence.Total)
} else {
fmt.Println("No winners :(")
}
}
``````

I won't go through the syntactical minutiae here, as I also need to write up my own answer using Go, and I think I use all the constructs in my code as are used here, so will discuss in one place.

It runs from the commandline, thus:

Sequence [100 60 60 60 60 60] wins with a length of 6  for a total of 400

That was the trickiest test, and it passed fine. I also ran the one that tripped up his original version:

No winners :(

It's good to see he's fixed that one.

This version is much more to the point than the previous version, which is good. Adam's had an interesting approach here: he extracts all the subseries which fall within the threshold, and then examines those to pull out the most fitting one. This'll be a byproduct of his initial approach which used parallel processing to expedite matters. He explains this on his initial entry which is on Github, here: https://github.com/adampresley/adamCameronCodeChallenge201411. One thing I do like about his initial take on things is to leverage Go-specific features like this. My approach with all languages so far has pretty much taken the same route, and is using very generic code: the logic and approach has always been the same, with the differences being down to how various languages implement the coding elements I'm using. This is useful too, as it makes for an interesting comparison, even if it's not the ideal approach to solving the challenge for the language concerned.

From a code perspective, I might have factored-out some of the phases here into helper functions:
• preprocess the command line args
• the main function which returns the result
• within that have sub functions for extracting the subseries
• and finding the best one
The `main()` function is pretty long here. And the comment blocks might not be necessary if the code was sub-functioned.

I'm bloody pleased Adam put both these entries in, especially the second one. I'd never set out to look at Go before, but our conversation has piqued my interest in it now. As a result I felt compelled to work through my own answer, which took about 8h in total to write, debug, test (yeah, sorry, no TDD on this one) and re-debug. The good thing is now I can understand Adam's code above just fine, and I think I'll put some effort into going through his initial entry now. I want to know about these "goroutines", for one thing.

Cheers mate!

--