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

时间:2019-07-12 13:19:45

标签: go

我需要从多个数组创建一个数组。新数组必须仅包含传入的所有数组中存在的值。例如。

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"]

该示例应返回["fiji", "brasil"],因为它们是所有数组中唯一的值。

我该如何去编写可以在golang中实现这一目标的函数?

这是我的尝试,但感觉有点笨拙

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
}

游乐场链接:https://play.golang.org/p/KRygw7OVBbn

3 个答案:

答案 0 :(得分:2)

根据我上面的评论,这是使用go map执行此操作的一种方法,因此避免了对可能较大的切片进行迭代:

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

答案 1 :(得分:0)

@colminator是一个有效的答案,但是算法不是最佳的。 @hallazang的建议是正确的方法,但是如果我们只需要一张地图,为什么还要创建两张地图呢?请参阅下一个选项以提高效率。

func repeatingItemsFromArrays(arrays ...[]string) []string {
    la := len(arrays)
    out := []string{}

    // handle corner cases for efficiency
    if la == 0 {
        return out
    }
    if la == 1 {
        return arrays[0]
    }

    m := make(map[string]int)

    for i := range arrays {
        for j := range arrays[i] {
            m[arrays[i][j]]++
        }
    }

    for k, v := range m {
        if v == la {
            out = append(out, k)
        }
    }

    return out
}

答案 2 :(得分:-1)

想法:

  1. 计数每个项目在数组(arr)中的出现次数。
  2. 如果该数字与len(arr)完全相同,则该项目将出现在所有数组中。

这是一个员工采用这种方法的示例:

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"]
}

和游乐场链接:https://play.golang.org/p/FB3wJ7-gaIa

编辑:即使每个数组中都有重复项,它也可以正常工作。