github.com/kazu/loncha@v0.6.3/uniq.go (about)

     1  // Copyright 2019 Kazuhisa TAKEI<xtakei@rytr.jp>. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package DeDuplication for slice.
     6  //
     7  // To Find from slice: (list is slice)
     8  //   loncha.Uniq(&list, func(i,j int) {
     9  //	 	return list[i].ID == list[j].ID
    10  //}
    11  
    12  package loncha
    13  
    14  import (
    15  	"reflect"
    16  	"sort"
    17  )
    18  
    19  type IdentFn func(i int) interface{}
    20  
    21  // Uniq is deduplicate using fn . if slice is not pointer of slice or empty, return error
    22  func Uniq(slice interface{}, fn IdentFn) error {
    23  
    24  	pRv, err := slice2Reflect(slice)
    25  	if err != nil {
    26  		return err
    27  	}
    28  	n := pRv.Elem().Len()
    29  
    30  	exists := make(map[interface{}]bool, n)
    31  
    32  	err = OldFilter(slice, func(i int) bool {
    33  		if !exists[fn(i)] {
    34  			exists[fn(i)] = true
    35  			return true
    36  		}
    37  		return false
    38  	})
    39  	exists = nil
    40  	return err
    41  }
    42  
    43  // Uniq2 is deduplicate using fn . if slice is not pointer of slice or empty, return error
    44  func Uniq2(slice interface{}, fn CompareFunc) error {
    45  
    46  	pRv, err := slice2Reflect(slice)
    47  	if err != nil {
    48  		return err
    49  	}
    50  	n := pRv.Elem().Len()
    51  
    52  	swap := reflect.Swapper(pRv.Elem().Interface())
    53  
    54  	uniqCnt := int(1)
    55  
    56  	for i := 0; i < n; i++ {
    57  		for j := 0; j < uniqCnt; j++ {
    58  			if fn(i, j) {
    59  				goto SKIP
    60  			}
    61  		}
    62  		swap(uniqCnt, i)
    63  		uniqCnt++
    64  	SKIP:
    65  	}
    66  	pRv.Elem().SetLen(uniqCnt)
    67  
    68  	return err
    69  }
    70  
    71  // UniqWithSort is deduplicating using fn, sorting before dedup. if slice is not pointer of slice or empty, return error
    72  func UniqWithSort(slice interface{}, fn CompareFunc) (int, error) {
    73  
    74  	pRv, err := slice2Reflect(slice)
    75  	if err != nil {
    76  		return -1, err
    77  	}
    78  	n := pRv.Elem().Len()
    79  
    80  	if !sort.SliceIsSorted(pRv.Elem().Interface(), fn) {
    81  		sort.Slice(pRv.Elem().Interface(), fn)
    82  	}
    83  	swap := reflect.Swapper(pRv.Elem().Interface())
    84  
    85  	a, b := 0, 1
    86  	for b < n {
    87  		if fn(a, b) {
    88  			a++
    89  			if a != b {
    90  				swap(a, b)
    91  			}
    92  		}
    93  		b++
    94  	}
    95  	return a + 1, nil
    96  
    97  }