Can we write a generic array/slice deduplication in go?

烈酒焚心 提交于 2019-12-04 10:06:33

问题


Is there a way to write a generic array/slice deduplication in go, for []int we can have something like (from http://rosettacode.org/wiki/Remove_duplicate_elements#Go ):

func uniq(list []int) []int {
  unique_set := make(map[int] bool, len(list))
  for _, x := range list {
     unique_set[x] = true
   }
  result := make([]int, len(unique_set))
  i := 0
  for x := range unique_set {
     result[i] = x
    i++
  }
  return result
}

But is there a way to extend it to support any array? with a signature like:

func deduplicate(a []interface{}) []interface{}

I know that you can write that function with that signature, but then you can't actually use it on []int, you need to create a []interface{} put everything from the []int into it, pass it to the function then get it back and put it into a []interface{} and go through this new array and put everything in a new []int.

My question is, is there a better way to do this?


回答1:


While VonC's answer probably does the closest to what you really want, the only real way to do it in native Go without gen is to define an interface

type IDList interface {
   // Returns the id of the element at i
   ID(i int) int

   // Returns the element
   // with the given id
   GetByID(id int) interface{}

   Len() int

   // Adds the element to the list
   Insert(interface{})
}

// Puts the deduplicated list in dst
func Deduplicate(dst, list IDList) {
    intList := make([]int, list.Len())
    for i := range intList {
        intList[i] = list.ID(i)
    }

    uniques := uniq(intList)
    for _,el := range uniques {
        dst.Insert(list.GetByID(el))
    }
}

Where uniq is the function from your OP.

This is just one possible example, and there are probably much better ones, but in general mapping each element to a unique "==able" ID and either constructing a new list or culling based on the deduplication of the IDs is probably the most intuitive way.

An alternate solution is to take in an []IDer where the IDer interface is just ID() int. However, that means that user code has to create the []IDer list and copy all the elements into that list, which is a bit ugly. It's cleaner for the user to wrap the list as an ID list rather than copy, but it's a similar amount of work either way.




回答2:


The only way I have seen that implemented in Go is with the clipperhouse/gen project,

gen is an attempt to bring some generics-like functionality to Go, with some inspiration from C#’s Linq and JavaScript’s underscore libraries

See this test:

// Distinct returns a new Thing1s slice whose elements are unique. See: http://clipperhouse.github.io/gen/#Distinct
func (rcv Thing1s) Distinct() (result Thing1s) {
    appended := make(map[Thing1]bool)
    for _, v := range rcv {
        if !appended[v] {
            result = append(result, v)
            appended[v] = true
        }
    }
    return result
}

But, as explained in clipperhouse.github.io/gen/:

gen generates code for your types, at development time, using the command line.

gen is not an import; the generated source becomes part of your project and takes no external dependencies.




回答3:


You could do something close to this via an interface. Define an interface, say "DeDupable" requiring a func, say, UniqId() []byte, which you could then use to do the removing of dups. and your uniq func would take a []DeDupable and work on it



来源:https://stackoverflow.com/questions/23275693/can-we-write-a-generic-array-slice-deduplication-in-go

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!