在Go中用切片检查子集

时间:2013-09-18 17:57:37

标签: arrays go subset slice

我正在寻找一种有效的方法来检查切片是否是另一个切片的子集。我可以简单地迭代它们来检查,但我觉得必须有更好的方法。

E.g。

  

{1,2,3}是{1,2,3,4}的子集   {1,2,2}不是{1,2,3,4}的子集

有效执行此操作的最佳方式是什么?

谢谢!

2 个答案:

答案 0 :(得分:5)

我认为解决子集问题的最常用方法是通过地图。

package main

import "fmt"

// subset returns true if the first array is completely
// contained in the second array. There must be at least
// the same number of duplicate values in second as there
// are in first.
func subset(first, second []int) bool {
    set := make(map[int]int)
    for _, value := range second {
        set[value] += 1
    }

    for _, value := range first {
        if count, found := set[value]; !found {
            return false
        } else if count < 1 {
            return false
        } else {
            set[value] = count - 1
        }
    }

    return true
}

func main() {
    fmt.Println(subset([]int{1, 2, 3}, []int{1, 2, 3, 4}))
    fmt.Println(subset([]int{1, 2, 2}, []int{1, 2, 3, 4}))
}

检查重复值的能力相对不常见。上面的代码解决了问题(参见:http://play.golang.org/p/4_7Oh-fgDQ)。如果您计划拥有重复值,则必须像上面的代码那样进行计数。如果不存在重复值,则可以通过对映射值使用布尔值而不是整数来更紧凑地解决问题。

答案 1 :(得分:0)

如果你的切片已经分类,这就完成了工作。

package main

import "fmt"

// Subset return whether a is a sublist of b. Both a and b must be (weakly) ascending.
func Subset(a, b []int) bool {
    for len(a) > 0 {
        switch {
        case len(b) == 0:
            return false
        case a[0] == b[0]:
            a = a[1:]
            b = b[1:]
        case a[0] < b[0]:
            return false
        case a[0] > b[0]:
            b = b[1:]
        }
    }
    return true
}

func main() {
    cases := []struct {
        a, b []int
        want bool
    }{
        {[]int{1, 2, 3}, []int{1, 2, 3, 4}, true},
        {[]int{1, 2, 2}, []int{1, 2, 3, 4}, false},
    }
    for _, c := range cases {
        if Subset(c.a, c.b) != c.want {
            fmt.Printf("Subset(%v, %v) = %v, want %v\n", c.a, c.b, Subset(c.a, c.b), c.want)
        }
    }
}