如何在golang中获得两个切片的交集?

时间:2017-07-06 18:04:04

标签: go

是否有任何有效的方法可以在Go中获得两个切片的交集?

我想避免嵌套for循环解决方案
slice1 := []string{"foo", "bar","hello"}
slice2 := []string{"foo", "bar"}

intersection(slice1, slice2)
=> ["foo", "bar"]
字符串的顺序无关紧要

5 个答案:

答案 0 :(得分:18)

How do I get the intersection between two arrays as a new array?

  • 简单交叉:将A中的每个元素与BO(n^2)
  • 中的每个元素进行比较
  • 哈希交点:将它们放入哈希表(O(n)
  • 排序交点:排序A并执行优化交叉点(O(n*log(n))

所有这些都在这里实施

https://github.com/juliangruber/go-intersect

答案 1 :(得分:1)

如果timespan = DateTime.Now.Subtract(Convert.ToDateTime(patientInfo[0].DOB)); Global.age = Convert.ToInt32(timespan.TotalDays) / 365; log.EventLog("DoB: " + patientInfo[0].DOB); log.EventLog("Scan Page Age: " + timespan.ToString() + " " + Global.age.ToString()); this.NavigationService.Navigate(Global.bmiPage); 中没有空白,也许您需要这个简单的代码:

[]string

答案 2 :(得分:1)

它是交叉双切片的最佳方法。时间复杂度太低了。

时间复杂度:O(m + n)

m =第一个切片的长度。

n =第二片的长度。

func intersection(s1, s2 []string) (inter []string) {
    hash := make(map[string]bool)
    for _, e := range s1 {
        hash[e] = true
    }
    for _, e := range s2 {
        // If elements present in the hashmap then append intersection list.
        if hash[e] {
            inter = append(inter, e)
        }
    }
    //Remove dups from slice.
    inter = removeDups(inter)
    return
}

//Remove dups from slice.
func removeDups(elements []string)(nodups []string) {
    encountered := make(map[string]bool)
    for _, element := range elements {
        if !encountered[element] {
            nodups = append(nodups, element)
            encountered[element] = true
        }
    }
    return
}

答案 3 :(得分:1)

https://github.com/viant/toolbox/blob/master/collections.go

另一个使用哈希图的O(m + n)时间复杂度解决方案。 与此处讨论的其他解决方案相比,它有两个区别。

  • 将目标切片作为参数传递,而不是返回新的切片
  • 更快地用于诸如string / int之类的常用类型,而不是全部反射

答案 4 :(得分:-1)

是的,有几种不同的方法可以解决它。这是一个可以优化的例子。

package main

import "fmt"

func intersection(a []string, b []string) (inter []string) {
    // interacting on the smallest list first can potentailly be faster...but not by much, worse case is the same
    low, high := a, b
    if len(a) > len(b) {
        low = b
        high = a
    }

    done := false
    for i, l := range low {
        for j, h := range high {
            // get future index values
            f1 := i + 1
            f2 := j + 1
            if l == h {
                inter = append(inter, h)
                if f1 < len(low) && f2 < len(high) {
                    // if the future values aren't the same then that's the end of the intersection
                    if low[f1] != high[f2] {
                        done = true
                    }
                }
                // we don't want to interate on the entire list everytime, so remove the parts we already looped on will make it faster each pass
                high = high[:j+copy(high[j:], high[j+1:])]
                break
            }
        }
        // nothing in the future so we are done
        if done {
            break
        }
    }
    return
}

func main() {
    slice1 := []string{"foo", "bar", "hello", "bar"}
    slice2 := []string{"foo", "bar"}
    fmt.Printf("%+v\n", intersection(slice1, slice2))
}

现在上面定义的交集方法只能在slices的{​​{1}}上运行,就像你的例子一样。理论上你可以创建一个看起来像strings的定义,但是你会依赖于反射和类型转换,以便您可以进行比较,这将增加延迟并使您的代码更难以阅读。维护和阅读可能更容易为您关心的每种类型编写单独的函数。

func intersection(a []interface, b []interface) (inter []interface)

func intersectionString(a []string, b []string) (inter []string)

func intersectionInt(a []int, b []int) (inter []int),.. ..

然后,您可以创建自己的包,并在确定要实现它的方式后重复使用。

func intersectionFloat64(a []Float64, b []Float64) (inter []Float64)