Golang从所有数组中存在的值创建数组

I need to create an array from multiple arrays. The new array must only contain the values that is present in all arrays passed in. For example.

array1 := []string{"hello", "germany", "brasil", "fiji"}
array2 := []string{"goodbye", "germany", "brasil", "fiji"}
array3 := []string{"hello", "brasil", "fiji"}
array4 := []string{"hello", "brasil", "fiji", "usa"}

func mergeArrays(arrs ...[]string) []string{
   // process arrays
}

myNewArray := mergeArrays(array1,array2,array3,array4)
fmt.Println(myNewArray) // ["fiji", "brasil"]

The example should return ["fiji", "brasil"] since they are the only values present in all arrays.

How could I go about writing a function that could achieve such a goal in golang?

This is my attempt but feels a bit clumsy

func mergeArrays(arrs ...[]string) []string {
    var finalArr []string
    if len(arrs) == 0 {
        return finalArr
    }

    for i, a := range arrs {
        if i == 0 {
            finalArr = arrs[0]
            continue
        }
        for i, e := range finalArr {
            if !strContains(a, e) {
                finalArr = append(finalArr[:i], finalArr[i+1:]...)
            }
        }

    }

    return finalArr
}

func strContains(s []string, e string) bool {
    for _, a := range s {
        if a == e {
            return true
        }
    }
    return false
}

Playground link: https://play.golang.org/p/KRygw7OVBbn

Per my comment above, here's one way to do it with go maps and thus avoid iterating over potentially large slices:

func itemize(a []string) map[string]struct{} {
    m := make(map[string]struct{})
    for _, v:=range a {
        m[v] = struct{}{} // struct{}{} == an empty struct (i.e. a value that incurs no storage)
    }
    return m
}

func commonElements(arrs ...[]string) (results []string) {
    if len(arrs) == 0 {
        return // edge case
    }

    mm := itemize(arrs[0]) // master map

    for i:=1; i<len(arrs);i++ {
        m := itemize(arrs[i]) // current map
        for k := range mm {
            if _, ok := m[k]; !ok {
                delete(mm, k) // master item not in current slice, so remove from master
            }
        }
    }

    results = make([]string, len(mm)) // make a precisely sized slice...
    i:=0
    for k := range mm {
        results[i] = k // so we can insert results directly into it without using append
        i++ 
    }

    return
}

https://play.golang.org/p/pTaXR-nY9zm

Idea:

  1. Count number of appearances of each item across arrays(arr).
  2. If that number is exactly same as len(arr), the item presents in all arrays.

Here's an example that employees this approach:

package main

import "fmt"

func uniq(arr []string) []string {
    cache := make(map[string]struct{})
    for _, s := range arr {
        cache[s] = struct{}{}
    }
    var r []string
    for s := range cache {
        r = append(r, s)
    }
    return r
}

func mergeArrays(arrs ...[]string) []string {
    count := make(map[string]int)
    for _, arr := range arrs {
        for _, s := range uniq(arr) {
            count[s]++
        }
    }
    var merged []string
    for s, n := range count {
        if n == len(arrs) {
            merged = append(merged, s)
        }
    }
    return merged
}

func main() {
    array1 := []string{"hello", "germany", "brasil", "fiji"}
    array2 := []string{"goodbye", "germany", "brasil", "fiji"}
    array3 := []string{"hello", "brasil", "fiji"}
    array4 := []string{"hello", "brasil", "fiji", "usa"}

    myNewArray := mergeArrays(array1, array2, array3, array4)
    fmt.Println(myNewArray) // ["fiji", "brasil"]
}

And playground link: https://play.golang.org/p/FB3wJ7-gaIa

EDIT: it will work properly even if there's any duplicate in each array.