【问题标题】:Golang create array from values present in all arraysGolang 从所有数组中存在的值创建数组
【发布时间】:2019-11-22 06:32:16
【问题描述】:

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

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

【问题讨论】:

  • 你试过了吗?您可以尝试一下吗?
  • @Adrian 更新问题以展示我尝试过的工作
  • @g4s8 我觉得我的用例有点不同
  • 使用 go map 跟踪唯一条目。使用第一个切片填充“主”映射(注意我使用了术语 slice 而不是数组 - 因为数组具有固定的不可变大小 - 您正在使用切片)。然后迭代剩余的切片,基于该切片创建单独的地图。通过此迭代主映射从主映射中删除不在此单独映射中的任何键。 Rince & 重复。最后输出剩余主映射键的切片 - 这将是所有切片共有的单词集。

标签: go


【解决方案1】:

@colminator's 是一个有效的答案,但算法不是最优的。 @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. 计算每个项目在数组中出现的次数(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

    编辑:即使每个数组中有任何重复,它也会正常工作。

    【讨论】:

      【解决方案3】:

      根据我上面的评论,这是使用 go maps 的一种方法,从而避免迭代潜在的大切片:

      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

      【讨论】:

        猜你喜欢
        • 2016-01-12
        • 1970-01-01
        • 2018-10-27
        • 2018-12-13
        • 2015-12-01
        • 2023-03-30
        • 1970-01-01
        • 2014-12-22
        • 1970-01-01
        相关资源
        最近更新 更多