RosettaCodeData/Task/Remove-duplicate-elements/Go/remove-duplicate-elements-4.go

91 lines
2.1 KiB
Go

package main
import (
"fmt"
"math"
"reflect"
)
func uniq(x interface{}) (interface{}, bool) {
v := reflect.ValueOf(x)
if !v.IsValid() {
panic("uniq: invalid argument")
}
if k := v.Kind(); k != reflect.Array && k != reflect.Slice {
panic("uniq: argument must be an array or a slice")
}
elemType := v.Type().Elem()
intType := reflect.TypeOf(int(0))
mapType := reflect.MapOf(elemType, intType)
m := reflect.MakeMap(mapType)
i := 0
for j := 0; j < v.Len(); j++ {
x := v.Index(j)
if m.MapIndex(x).IsValid() {
continue
}
m.SetMapIndex(x, reflect.ValueOf(i))
if m.MapIndex(x).IsValid() {
i++
}
}
sliceType := reflect.SliceOf(elemType)
result := reflect.MakeSlice(sliceType, i, i)
hadNaN := false
for _, key := range m.MapKeys() {
ival := m.MapIndex(key)
if !ival.IsValid() {
hadNaN = true
} else {
result.Index(int(ival.Int())).Set(key)
}
}
return result.Interface(), hadNaN
}
type MyType struct {
name string
value float32
}
func main() {
intArray := [...]int{5, 1, 2, 3, 2, 3, 4}
intSlice := []int{5, 1, 2, 3, 2, 3, 4}
stringSlice := []string{"five", "one", "two", "three", "two", "three", "four"}
floats := []float64{1, 2, 2, 4,
math.NaN(), 2, math.NaN(),
math.Inf(1), math.Inf(1), math.Inf(-1), math.Inf(-1)}
complexes := []complex128{1, 1i, 1 + 1i, 1 + 1i,
complex(math.NaN(), 1), complex(1, math.NaN()),
complex(math.Inf(+1), 1), complex(1, math.Inf(1)),
complex(math.Inf(-1), 1), complex(1, math.Inf(1)),
}
structs := []MyType{
{"foo", 42},
{"foo", 2},
{"foo", 42},
{"bar", 42},
{"bar", 2},
{"fail", float32(math.NaN())},
}
fmt.Print("intArray: ", intArray, " → ")
fmt.Println(uniq(intArray))
fmt.Print("intSlice: ", intSlice, " → ")
fmt.Println(uniq(intSlice))
fmt.Print("stringSlice: ", stringSlice, " → ")
fmt.Println(uniq(stringSlice))
fmt.Print("floats: ", floats, " → ")
fmt.Println(uniq(floats))
fmt.Print("complexes: ", complexes, "\n → ")
fmt.Println(uniq(complexes))
fmt.Print("structs: ", structs, " → ")
fmt.Println(uniq(structs))
// Passing a non slice or array will compile put
// then produce a run time panic:
//a := 42
//uniq(a)
//uniq(nil)
}