Go如何對數組切片進行去重

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值類型爲空structmap,等效於使用make(map[string]struct{})
  • struct不佔內存空間,使用它來實現我們的函數空間複雜度是最低的。

Playground URL
Reference URL

適配多個切片類型

上面的去除重複元素的函數,只能處理字符串切片對於其他類型的切片就不行了。如果不想針對每種類型的切片都寫一個去重函數的話可以使用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值類型爲空structmap。key的值是切片元素的字符串表現形式(類型的String()方法的返回值)
  • 函數返回值的類型是空接口,所以拿到返回值後要進行類型斷言才能使用。

原文鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章