kevinyan815 / gocookbook

go cook book
MIT License
789 stars 167 forks source link

Slice过滤重复元素 #5

Open kevinyan815 opened 5 years ago

kevinyan815 commented 5 years ago

Slice去除重复元素

golang标准库本身没有提供一个去除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
}

解释

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
    }
}
yuemingming commented 6 months ago
func distinct[T comparable](input []T) []T {
    set := make(map[T]struct{})
    res := make([]T, 0, len(set))
    for _, value := range input {
        if _, ok := set[value]; !ok {
            set[value] = struct{}{}
            res = append(res, value)
        }
    }
    return res
}

提供一个泛型实现