1

Here is a word-count function in Go

package wc

import (
    "regexp"
    "strings"
)

type Histogram map[string]int

func WordCount(input string) Histogram {
    histogram := make(map[string]int)
    re := regexp.MustCompile("[^a-zA-Z0-9 ]*")
    input = re.ReplaceAllString(input, "")

    for _, word := range strings.Split(input, " ") {
        if word == "" {
            continue
        }
        histogram[strings.ToLower(word)]++
    }

    return histogram
}

This code passes or fails the tests non-deterministically. Sometimes it failed due to not matching the expected map and the actual map. However, the contents of both are exactly the same. I think that there is some problem with map comparison. I don't know how can I fix it. Somebody help me please!

Here is the test-suite code

package wc

import (
    "fmt"
    "testing"
)

var testCases = []struct {
    description string
    input       string
    output      Histogram
}{
    {
        description: "a single word",
        input:       "word",
        output:      Histogram{"word": 1},
    },
    {
        description: "one of each",
        input:       "one of each",
        output:      Histogram{"one": 1, "of": 1, "each": 1},
    },
    {
        description: "multiple occurrences",
        input:       "one fish two fish red fish blue fish",
        output:      Histogram{"one": 1, "fish": 4, "two": 1, "red": 1, "blue": 1},
    },
    {
        description: "ignore punctuation",
        input:       "car : carpet as java : javascript!!&@$%^&",
        output:      Histogram{"car": 1, "carpet": 1, "as": 1, "java": 1, "javascript": 1},
    },
    {
        description: "including numbers",
        input:       "testing, 1, 2 testing",
        output:      Histogram{"testing": 2, "1": 1, "2": 1},
    },
    {
        description: "normalises case",
        input:       "go Go GO",
        output:      Histogram{"go": 3},
    },
}

func TestWordCount(t *testing.T) {
    for _, tt := range testCases {
        expected := fmt.Sprintf("%v", tt.output)
        actual := fmt.Sprintf("%v", WordCount(tt.input))

        if expected != actual {
            t.Fatalf("%s\n\tExpected: %v\n\tGot: %v", tt.description, expected, actual)
        } else {
            t.Logf("PASS: %s - WordCount(%s)", tt.description, tt.input)
        }
    }
}

Below are examples of the failure situation:

1.
Expected: map[two:1 red:1 blue:1 one:1 fish:4]
Got: map[one:1 fish:4 two:1 red:1 blue:1]
2.
Expected: map[one:1 fish:4 two:1 red:1 blue:1]
Got: map[red:1 blue:1 one:1 fish:4 two:1]
3.
Expected: map[java:1 javascript:1 car:1 carpet:1 as:1]
Got: map[javascript:1 car:1 carpet:1 as:1 java:1]
...

Additional information are here: http://exercism.io/submissions/cf94f4732fd97335be2e755f

Rick-777
  • 9,714
  • 5
  • 34
  • 50
ChangHun Lee
  • 127
  • 1
  • 12

2 Answers2

3

You can't compare expected and actual with !=, because it compares the string representation of the maps, so it will work only randomly (if the values are printed in the same order).

What you have to do, is to use the reflect package DeepEqual() method to compare the maps :

import "reflect"
// ...

if !reflect.DeepEqual(tt.output, WordCount(tt.input)) {
// ...

It will first checks if both maps are nil, then if they have the same length, then if they have the same set of (key, value) pairs.

Florent Bayle
  • 11,520
  • 4
  • 34
  • 47
  • I've tried this but it doesn't work(I got same results with above). I don't know why. – ChangHun Lee Feb 13 '14 at 05:39
  • I know how can I solve this problem with the manually way. However I would like to discuss about this problem. Why `!reflect.DeepEqual` method doesn't work with this problem? – ChangHun Lee Feb 13 '14 at 05:58
  • 1
    @ChangHunLee Oops, my bad, you have to compare the maps `!reflect.DeepEqual(tt.output, WordCount(tt.input))` and not `expected` and `actual` (which are the strings). – Florent Bayle Feb 13 '14 at 05:58
  • @ChangHunLee I've edited the answer with the correction. – Florent Bayle Feb 13 '14 at 06:00
  • Yes! I was realized my fault! Thank you! – ChangHun Lee Feb 13 '14 at 06:03
  • "You can't compare the two maps with !=, because it compares the string representation of the maps" You can't compare two maps with != ever. Not "because" of anything. And he's not comparing maps with !=; he's comparing string representations. That's two different things. – newacct Feb 13 '14 at 21:33
  • @newacct Yes, wrong formulation, I edited the answer to correct it. Thanks. – Florent Bayle Feb 13 '14 at 23:40
2

You are not comparing two maps, you are comparing the String() output of two maps. However, when a map is printed or range()'d, the content is randomly picked, so you cannot compare it with strings.

You could compare lengths first, then range() one of them and check if the value of every key in the first map is present and equal to the value of the same key in the second map.

siritinga
  • 4,063
  • 25
  • 38
  • Do I have to do this manually? I would like to find some way or method to solve this problem at once. I found `reflect.DeepEqual` method. But it doesn't work. Is this bug of Go? – ChangHun Lee Feb 13 '14 at 05:55