How to find the difference between two slices of strings

I use the map to solve this problem

package main

import "fmt"

func main() {
    slice1 := []string{"foo", "bar","hello"}
    slice2 := []string{"foo", "bar","world"}

    diffStr := difference(slice1, slice2)

    for _, diffVal := range diffStr {
        fmt.Println(diffVal)
    }

}

func difference(slice1 []string, slice2 []string) ([]string){
    diffStr := []string{}
    m :=map [string]int{}

    for _, s1Val := range slice1 {
        m[s1Val] = 1
    }
    for _, s2Val := range slice2 {
        m[s2Val] = m[s2Val] + 1
    }

    for mKey, mVal := range m {
        if mVal==1 {
            diffStr = append(diffStr, mKey)
        }
    }

    return diffStr
}

output:
hello
world


Assuming Go maps are ~O(1), here is an ~O(n) difference function that works on unsorted slices.

// difference returns the elements in `a` that aren't in `b`.
func difference(a, b []string) []string {
    mb := make(map[string]struct{}, len(b))
    for _, x := range b {
        mb[x] = struct{}{}
    }
    var diff []string
    for _, x := range a {
        if _, found := mb[x]; !found {
            diff = append(diff, x)
        }
    }
    return diff
}

Depending on the size of the slices, different solutions might be best.

My answer assumes order doesn't matter.

Using simple loops, only to be used with smaller slices:

package main

import "fmt"

func difference(slice1 []string, slice2 []string) []string {
    var diff []string

    // Loop two times, first to find slice1 strings not in slice2,
    // second loop to find slice2 strings not in slice1
    for i := 0; i < 2; i++ {
        for _, s1 := range slice1 {
            found := false
            for _, s2 := range slice2 {
                if s1 == s2 {
                    found = true
                    break
                }
            }
            // String not found. We add it to return slice
            if !found {
                diff = append(diff, s1)
            }
        }
        // Swap the slices, only if it was the first loop
        if i == 0 {
            slice1, slice2 = slice2, slice1
        }
    }

    return diff
}

func main() {
    slice1 := []string{"foo", "bar", "hello"}
    slice2 := []string{"foo", "world", "bar", "foo"}

    fmt.Printf("%+v\n", difference(slice1, slice2))
}

Output:

[hello world]

Playground: http://play.golang.org/p/KHTmJcR4rg

Tags:

Go