Go標準庫本身沒有提供一個去除slice中重複元素的函式,需要自己去實現。下面提供一種實現思路,如果有更好的實現方法歡迎留言討論。
package main
import (
"fmt"
)
func main() {
s := []string{"hello", "world", "hello", "golang", "hello", "ruby", "php", "java"}
fmt.Println(removeDuplicateElement(s)) //output: hello world golang ruby php java
}
func removeDuplicateElement(languages []string) []string {
result := make([]string, 0, len(languages))
temp := map[string]struct{}{}
for _, item := range languages {
if _, ok := temp[item]; !ok {
temp[item] = struct{}{}
result = append(result, item)
}
}
return result
}
解釋
removeDuplicateElement
函式總共初始化兩個變數,一個長度為0的slice
,一個空map
。由於slice
傳參是按引用傳遞,沒有建立佔用額外的記憶體空間。map[string]struct{}{}
建立了一個key型別為String值型別為空struct
的map
,等效於使用make(map[string]struct{})
- 空
struct
不佔記憶體空間,使用它來實現我們的函式空間複雜度是最低的。
適配多個切片型別
上面的去除重複元素的函式,只能處理字串切片對於其他型別的切片就不行了。如果不想針對每種型別的切片都寫一個去重函式的話可以使用Go的type-switch自己寫一個可以處理多個切片型別的函式。下面是我寫的一個實現:
package common
import (
"fmt"
)
type sliceError struct {
msg string
}
func (e *sliceError) Error() string {
return e.msg
}
func Errorf(format string, args ...interface{}) error {
msg := fmt.Sprintf(format, args...)
return &sliceError{msg}
}
func removeDuplicateElement1(originals interface{}) (interface{}, error) {
temp := map[string]struct{}{}
switch slice := originals.(type) {
case []string:
result := make([]string, 0, len(originals.([]string)))
for _, item := range slice {
key := fmt.Sprint(item)
if _, ok := temp[key]; !ok {
temp[key] = struct{}{}
result = append(result, item)
}
}
return result, nil
case []int64:
result := make([]int64, 0, len(originals.([]int64)))
for _, item := range slice {
key := fmt.Sprint(item)
if _, ok := temp[key]; !ok {
temp[key] = struct{}{}
result = append(result, item)
}
}
return result, nil
default:
err := Errorf("Unknown type: %T", slice)
return nil, err
}
}
-
函式接收一個空介面型別的引數,然後使用型別選擇進入相應的分支進行處理。這裡可以根據需求新增函式需支援的切片型別的處理程式。
-
每個分支裡同樣建立了一個key型別為string值型別為空
struct
的map
。key的值是切片元素的字串表現形式(型別的String()
方法的返回值) -
函式返回值的型別是空介面,所以拿到返回值後要進行型別斷言才能使用。