Finding common elements between two slices is a frequent task in many programming applications. Go provides us with the ability to manipulate slices and in this article, we’ll look at different approaches to identify common elements across two slices.
Basic Approach: Nested Loops
This is the simplest and most intuitive method. We iterate through both slices and compare their elements, collecting matches into a new slice.
package main
import "fmt"
func findCommonElements(slice1, slice2 []int) []int {
commonElements := []int{}
for _, elem1 := range slice1 {
for _, elem2 := range slice2 {
if elem1 == elem2 {
commonElements = append(commonElements, elem1)
break
}
}
}
return commonElements
}
func main() {
slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{3, 4, 5, 6, 7}
fmt.Println(findCommonElements(slice1, slice2)) // Output: [3 4 5]
}Intermediate Approach: Using a Map
A more efficient way is to utilize a map to record the occurrence of elements from one slice and then iterate over the other slice to find common elements. This approach reduces the time complexity to O(n + m), where n and m are the lengths of the slices.
package main
import "fmt"
func findCommonElements(slice1, slice2 []int) []int {
elementMap := make(map[int]bool)
commonElements := []int{}
for _, elem1 := range slice1 {
elementMap[elem1] = true
}
for _, elem2 := range slice2 {
if elementMap[elem2] {
commonElements = append(commonElements, elem2)
}
}
return commonElements
}
func main() {
slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{3, 4, 5, 6, 7}
fmt.Println(findCommonElements(slice1, slice2)) // Output: [3 4 5]
}Advanced Approach: Using Generic Functions
If you need a more generic function that can handle slices of any type, you can utilize Go's new type parameter feature. This method is more versatile and can handle different types, but it requires more advanced Go specification.
package main
import "fmt"
func findCommonElements[T comparable](slice1, slice2 []T) []T {
elementMap := make(map[T]bool)
commonElements := []T{}
for _, elem1 := range slice1 {
elementMap[elem1] = true
}
for _, elem2 := range slice2 {
if elementMap[elem2] {
commonElements = append(commonElements, elem2)
}
}
return commonElements
}
func main() {
slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{3, 4, 5, 6, 7}
fmt.Println(findCommonElements(slice1, slice2)) // Output: [3 4 5]
slice3 := []string{"apple", "banana", "mango"}
slice4 := []string{"banana", "kiwi", "mango"}
fmt.Println(findCommonElements(slice3, slice4)) // Output: [banana mango]
}Each of these approaches has its place. The basic approach is straightforward but may be inefficient for large slices due to its O(n*m) complexity. Using a map optimizes the process significantly. The generic function, taking advantage of Go's type system, provides flexibility if you're working with varied types.