Existe-t-il un moyen efficace d'obtenir l'intersection de deux tranches dans Go?
slice1 := []string{"foo", "bar","hello"}
slice2 := []string{"foo", "bar"}
intersection(slice1, slice2)
=> ["foo", "bar"]
Oui, il y a différentes façons de s'y prendre. Voici un exemple qui peut être optimisé.
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))
}
Maintenant, la méthode d'intersection définie ci-dessus ne fonctionnera que sur slices
de strings
, comme dans votre exemple .. Vous pouvez théoriquement créer une définition ressemblant à ceci func intersection(a []interface, b []interface) (inter []interface)
. ajouter de la latence et rendre votre code plus difficile à lire. Il est probablement plus facile de maintenir et de lire pour écrire une fonction distincte pour chaque type de personne qui compte pour vous.
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
Vous pouvez ensuite créer votre propre package et le réutiliser une fois que vous avez défini comment vous souhaitez le mettre en œuvre.
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)
Comment obtenir l'intersection de deux tableaux en tant que nouveau tableau?
A
à chacun dans B
(O(n^2)
)O(n)
)A
et faites une intersection optimisée (O(n*log(n))
)Tous sont mis en œuvre ici
s'il n'y a pas de blanc dans votre []string
, vous avez peut-être besoin de ce code simple:
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
}
https://github.com/viant/toolbox/blob/master/collections.go
Une autre solution de complexité temporelle O (m + n) utilisant un hashmap. Il a deux différences par rapport aux autres solutions discutées ici.
C'est une meilleure méthode pour l'intersection de deux tranches. La complexité temporelle est trop faible.
Complexité temporelle: O (m + n)
m = longueur de la première tranche.
n = longueur de la deuxième tranche.
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
}