英文:
How to get intersection of two slice in golang?
问题
有没有一种高效的方法在Go语言中获取两个切片的交集?
我想避免像嵌套循环那样的解决方案
slice1 := []string{"foo", "bar", "hello"}
slice2 := []string{"foo", "bar"}
intersection(slice1, slice2)
=> ["foo", "bar"]
字符串的顺序不重要
英文:
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"}
slice2 := []string{"foo", "bar"}
intersection(slice1, slice2)
=> ["foo", "bar"]
order of string does not matter
答案1
得分: 38
以下是要翻译的内容:
- 简单交集:将
A
中的每个元素与B
中的每个元素进行比较(O(n^2)
) - 哈希交集:将它们放入哈希表中(
O(n)
) - 排序交集:对
A
进行排序并进行优化的交集操作(O(n*log(n))
)
这些方法在这里实现:
https://github.com/juliangruber/go-intersect/blob/master/intersect.go
英文:
- Simple Intersection: Compare each element in
A
to each inB
(O(n^2)
) - Hash Intersection: Put them into a hash table (
O(n)
) - Sorted Intersection: Sort
A
and do an optimized intersection (O(n*log(n))
)
All of which are implemented here
https://github.com/juliangruber/go-intersect/blob/master/intersect.go
答案2
得分: 5
简单、通用和多个切片!(Go 1.18)
时间复杂度:可能是线性的
func interSection[T constraints.Ordered](pS ...[]T) []T {
hash := make(map[T]*int) // value, counter
result := make([]T, 0)
for _, slice := range pS {
duplicationHash := make(map[T]bool) // duplication checking for individual slice
for _, value := range slice {
if _, isDup := duplicationHash[value]; !isDup { // is not duplicated in slice
if counter := hash[value]; counter != nil { // is found in hash counter map
if *counter++; *counter >= len(pS) { // is found in every slice
result = append(result, value)
}
} else { // not found in hash counter map
i := 1
hash[value] = &i
}
duplicationHash[value] = true
}
}
}
return result
}
func main() {
slice1 := []string{"foo", "bar", "hello"}
slice2 := []string{"foo", "bar"}
fmt.Println(interSection(slice1, slice2))
// [foo bar]
ints1 := []int{1, 2, 3, 9, 8}
ints2 := []int{10, 4, 2, 4, 8, 9} // have duplicated values
ints3 := []int{2, 4, 8, 1}
fmt.Println(interSection(ints1, ints2, ints3))
// [2 8]
}
playground: https://go.dev/play/p/lE79D0kOznZ
请注意,这是一段使用Go语言编写的代码,用于计算多个切片的交集。它使用了哈希表和计数器来实现。在给定的切片中,如果一个元素在每个切片中都出现,则将其添加到结果切片中。这段代码可以在Go Playground上运行。
英文:
simple, generic and mutiple slices ! (Go 1.18)
Time Complexity : may be linear
func interSection[T constraints.Ordered](pS ...[]T) []T {
hash := make(map[T]*int) // value, counter
result := make([]T, 0)
for _, slice := range pS {
duplicationHash := make(map[T]bool) // duplication checking for individual slice
for _, value := range slice {
if _, isDup := duplicationHash[value]; !isDup { // is not duplicated in slice
if counter := hash[value]; counter != nil { // is found in hash counter map
if *counter++; *counter >= len(pS) { // is found in every slice
result = append(result, value)
}
} else { // not found in hash counter map
i := 1
hash[value] = &i
}
duplicationHash[value] = true
}
}
}
return result
}
func main() {
slice1 := []string{"foo", "bar", "hello"}
slice2 := []string{"foo", "bar"}
fmt.Println(interSection(slice1, slice2))
// [foo bar]
ints1 := []int{1, 2, 3, 9, 8}
ints2 := []int{10, 4, 2, 4, 8, 9} // have duplicated values
ints3 := []int{2, 4, 8, 1}
fmt.Println(interSection(ints1, ints2, ints3))
// [2 8]
}
playground : https://go.dev/play/p/lE79D0kOznZ
答案3
得分: 4
这是一个计算两个切片交集的最佳方法。时间复杂度非常低。
时间复杂度: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 hash[e] {
inter = append(inter, e)
}
}
// 从切片中删除重复项。
inter = removeDups(inter)
return
}
// 从切片中删除重复项。
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
}
希望对你有帮助!
英文:
It's a best method for intersection two slice. Time complexity is too low.
Time Complexity : O(m+n)
m = length of first slice.
n = length of second slice.
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
}
答案4
得分: 2
如果在你的[]string
中不存在空白,也许你需要这段简单的代码:
func filter(src []string) (res []string) {
for _, s := range src {
newStr := strings.Join(res, " ")
if !strings.Contains(newStr, s) {
res = append(res, s)
}
}
return
}
func intersections(section1, section2 []string) (intersection []string) {
str1 := strings.Join(filter(section1), " ")
for _, s := range filter(section2) {
if strings.Contains(str1, s) {
intersection = append(intersection, s)
}
}
return
}
英文:
if there exists no blank in your []string
, maybe you need this simple code:
func filter(src []string) (res []string) {
for _, s := range src {
newStr := strings.Join(res, " ")
if !strings.Contains(newStr, s) {
res = append(res, s)
}
}
return
}
func intersections(section1, section2 []string) (intersection []string) {
str1 := strings.Join(filter(section1), " ")
for _, s := range filter(section2) {
if strings.Contains(str1, s) {
intersection = append(intersection, s)
}
}
return
}
答案5
得分: 1
另一个时间复杂度为O(m+n)的解决方案,使用了哈希映射。与此处讨论的其他解决方案相比,它有两个不同之处:
- 将目标切片作为参数传递,而不是返回一个新的切片
- 对于常用类型(如字符串/整数),使用速度更快,而不是对所有类型进行反射操作
你可以在以下链接中找到代码实现的详细内容:
https://github.com/viant/toolbox/blob/a46fd679bbc5d07294b1d1b646aeacd44e2c7d50/collections.go#L869-L920
英文:
Another O(m+n) Time Complexity solution that uses a hashmap.
It has two differences compared to the other solutions discussed here.
- Passing the target slice as a parameter instead of new slice returned
- Faster to use for commonly used types like string/int instead of reflection for all
答案6
得分: 1
尝试一下
https://go.dev/play/p/eGGcyIlZD6y
first := []string{"one", "two", "three", "four"}
second := []string{"two", "four"}
result := intersection(first, second) // 或者 intersection(second, first)
func intersection(first, second []string) []string {
out := []string{}
bucket := map[string]bool{}
for _, i := range first {
for _, j := range second {
if i == j && !bucket[i] {
out = append(out, i)
bucket[i] = true
}
}
}
return out
}
英文:
Try it
https://go.dev/play/p/eGGcyIlZD6y
first := []string{"one", "two", "three", "four"}
second := []string{"two", "four"}
result := intersection(first, second) // or intersection(second, first)
func intersection(first, second []string) []string {
out := []string{}
bucket := map[string]bool{}
for _, i := range first {
for _, j := range second {
if i == j && !bucket[i] {
out = append(out, i)
bucket[i] = true
}
}
}
return out
}
答案7
得分: -8
是的,有几种不同的方法可以实现这个功能。这里有一个可以进行优化的示例。
package main
import "fmt"
func intersection(a []string, b []string) (inter []string) {
// 首先交互较小的列表可能会更快...但差别不大,最坏情况下是相同的
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 {
// 获取未来的索引值
f1 := i + 1
f2 := j + 1
if l == h {
inter = append(inter, h)
if f1 < len(low) && f2 < len(high) {
// 如果未来的值不相同,那就是交集的结束
if low[f1] != high[f2] {
done = true
}
}
// 我们不想每次都遍历整个列表,所以删除已经遍历过的部分会使每次遍历更快
high = high[:j+copy(high[j:], high[j+1:])]
break
}
}
// 没有未来的值,所以我们完成了
if done {
break
}
}
return
}
func main() {
slice1 := []string{"foo", "bar", "hello", "bar"}
slice2 := []string{"foo", "bar"}
fmt.Printf("%+v\n", intersection(slice1, slice2))
}
现在上面定义的intersection
方法只能操作[]string
类型的切片,就像你的示例一样。理论上,你可以创建一个定义如下的方法: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)
然后,你可以创建自己的包,并在确定了如何实现后进行重用。
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)
希望这可以帮助到你!
英文:
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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论