Thinking Backwards

2 minute read Published:

Sometimes backwards is best.

This is just a quick post on something I ran across for work and I though was interesting. I study Japanese and there is some research pointing to the fact that language can affect the way you think. I recently ran across a situation and wanted to discuss it briefly.

I was tasked with something quite simple. The problem was this: Take a list of strings and create an output that displays the list using natural english. The order of the output is inconsequential.

Example:

[“usagi”,“kitsune”] would producte the output: usagi and kitsune [“usagi”,“kitsune”,“kuma”] would product the output: usagi, kitsune and kuma. It also could produce kuma, kitsune and usagi. The order does not matter.

Let’s write a program:

Test Cases: I’ll write a quick table driven test here to check the empty list edge case and then a list with one, two, three and four strings. Since we will be working backwards the test needs to reflect that. Here is the test code:

naturalList_test.go

package main

import (
    "testing"
)

func TestNaturalList(t *testing.T) {
    var nlTests = []struct {
        srcList []string
        result  string
    }{
        {[]string{""}, ""},
        {[]string{"kitsune"}, "kitsune"},
        {[]string{"kitsune", "usagi"}, "usagi and kitsune"},
        {[]string{"kitsune", "usagi", "kuma"}, "kuma, usagi and kitsune"},
        {[]string{"kitsune", "usagi", "kuma", "zou"}, "zou, kuma, usagi and kitsune"}}

    for _, c := range nlTests {
        nlRlt := NaturalList(c.srcList)
        if c.result != NaturalList(c.srcList) {
            t.Fatalf("Test Failed: Expected %s got %s", c.result, nlRlt)
        }
    }
}

Now let’s move on to the implementation:

naturalList.go

package naturalList

const (
    primary_connector = ", "
    final_connector   = " and "
)

//NaturalList takes a list of strings and returns
//a syntactically correct ordered English list. The
//order of words does not matter.
func NaturalList(sl []string) (rlt string) {
    for i, cs := range sl {
        rlt = cs + rlt
        if (i == 0) && (len(sl) > 1) {
            rlt = final_connector + rlt
            continue
        }
        if i != (len(sl) - 1) {
            rlt = primary_connector + rlt
        }
    }
    return
}

I suppose there could be another way to do this, but this way seemed simple and elegant. If you needed to preserve order, this algorithm would work but you would need a utility function to reverse the order of the input string list.

This was a neat excercise and I thought it would be nice to share.