How to get intersection of two slice in golang?

前端 未结 5 1556
不思量自难忘°
不思量自难忘° 2021-02-18 22:24

Is there any efficient way to get intersection of two slices in Go?

I want to avoid nested for loop like solution
slice1 := []string{\"foo\", \"bar\",\"hello\"}         


        
5条回答
  •  旧时难觅i
    2021-02-18 23:12

    Yes there are a few different ways to go about it.. Here's an example that can be optimized.

    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))
    }
    

    Now the intersection method defined above will only operate on slices of strings, like your example.. You can in theory create a definition that looks like this func intersection(a []interface, b []interface) (inter []interface), however you would be relying on reflection and type casting so that you can compare, which will add latency and make your code harder to read. It's probably easier to maintain and read to write a separate function for each type you care about.

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

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

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

    You can then create your own package and reuse once you settle how you want to implement it.

    package intersection
    
    func String(a []string, b []string) (inter []string)
    
    func Int(a []int, b []int) (inter []int)
    
    func Float64(a []Float64, b []Float64) (inter []Float64)
    

提交回复
热议问题