github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/zarray/slice.go (about)

     1  //go:build go1.18
     2  // +build go1.18
     3  
     4  package zarray
     5  
     6  import (
     7  	"math/rand"
     8  
     9  	"github.com/sohaha/zlsgo/zstring"
    10  	"github.com/sohaha/zlsgo/zsync"
    11  	"github.com/sohaha/zlsgo/zutil"
    12  )
    13  
    14  // CopySlice copy a slice.
    15  func CopySlice[T any](l []T) []T {
    16  	nl := make([]T, len(l))
    17  	copy(nl, l)
    18  	return nl
    19  }
    20  
    21  // Rand A random eents.
    22  func Rand[T any](collection []T) T {
    23  	l := len(collection)
    24  	if l == 0 {
    25  		var zero T
    26  		return zero
    27  	}
    28  
    29  	i := zstring.RandInt(0, l-1)
    30  	return collection[i]
    31  }
    32  
    33  // Map manipulates a slice and transforms it to a slice of another type.
    34  func Map[T any, R any](collection []T, iteratee func(int, T) R) []R {
    35  	res := make([]R, len(collection))
    36  
    37  	for i, item := range collection {
    38  		res[i] = iteratee(i, item)
    39  	}
    40  
    41  	return res
    42  }
    43  
    44  // ParallelMap Parallel manipulates a slice and transforms it to a slice of another type.
    45  // If the calculation does not involve time-consuming operations, we recommend using a Map.
    46  func ParallelMap[T any, R any](collection []T, iteratee func(int, T) R, workers uint) []R {
    47  	inLen, workTotal := len(collection), int(workers)
    48  
    49  	res := make([]R, inLen)
    50  	if inLen == 0 {
    51  		return res
    52  	}
    53  
    54  	if inLen < workTotal {
    55  		workTotal = inLen
    56  	} else if workTotal == 0 {
    57  		workTotal = 1
    58  	}
    59  
    60  	idx := zutil.NewInt64(0)
    61  	task := func() {
    62  		i := int(idx.Add(1) - 1)
    63  		for ; i < inLen; i = int(idx.Add(1) - 1) {
    64  			res[i] = iteratee(i, collection[i])
    65  		}
    66  	}
    67  
    68  	var wg zsync.WaitGroup
    69  	for i := 0; i < workTotal; i++ {
    70  		wg.Go(task)
    71  	}
    72  	_ = wg.Wait()
    73  
    74  	return res
    75  }
    76  
    77  // Shuffle creates a slice of shuffled values.
    78  func Shuffle[T any](collection []T) []T {
    79  	n := CopySlice(collection)
    80  	rand.Shuffle(len(n), func(i, j int) {
    81  		n[i], n[j] = n[j], n[i]
    82  	})
    83  
    84  	return n
    85  }
    86  
    87  // Reverse creates a slice of reversed values.
    88  func Reverse[T any](collection []T) []T {
    89  	n := CopySlice(collection)
    90  	l := len(n)
    91  	for i := 0; i < l/2; i++ {
    92  		n[i], n[l-i-1] = n[l-i-1], n[i]
    93  	}
    94  
    95  	return n
    96  }
    97  
    98  // Filter iterates over eents of collection.
    99  func Filter[T any](slice []T, predicate func(index int, item T) bool) []T {
   100  	slice = CopySlice(slice)
   101  
   102  	j := 0
   103  	for i := range slice {
   104  		if !predicate(i, slice[i]) {
   105  			continue
   106  		}
   107  		slice[j] = slice[i]
   108  		j++
   109  	}
   110  
   111  	return slice[:j:j]
   112  }
   113  
   114  // Contains returns true if an eent is present in a collection.
   115  func Contains[T comparable](collection []T, v T) bool {
   116  	for _, item := range collection {
   117  		if item == v {
   118  			return true
   119  		}
   120  	}
   121  
   122  	return false
   123  }
   124  
   125  // Find search an eent in a slice based on a predicate. It returns eent and true if eent was found.
   126  func Find[T any](collection []T, predicate func(index int, item T) bool) (res T, ok bool) {
   127  	for i := range collection {
   128  		item := collection[i]
   129  		if predicate(i, item) {
   130  			return item, true
   131  		}
   132  	}
   133  
   134  	return
   135  }
   136  
   137  // Unique returns a duplicate-free version of an array.
   138  func Unique[T comparable](collection []T) []T {
   139  	repeat := make(map[T]struct{}, len(collection))
   140  
   141  	return Filter(collection, func(_ int, item T) bool {
   142  		if _, ok := repeat[item]; ok {
   143  			return false
   144  		}
   145  		repeat[item] = struct{}{}
   146  		return true
   147  	})
   148  }
   149  
   150  // Diff returns the difference between two slices.
   151  func Diff[T comparable](list1 []T, list2 []T) ([]T, []T) {
   152  	l, r := []T{}, []T{}
   153  
   154  	rl, rr := map[T]struct{}{}, map[T]struct{}{}
   155  
   156  	for _, e := range list1 {
   157  		rl[e] = struct{}{}
   158  	}
   159  
   160  	for _, e := range list2 {
   161  		rr[e] = struct{}{}
   162  	}
   163  
   164  	for _, e := range list1 {
   165  		if _, ok := rr[e]; !ok {
   166  			l = append(l, e)
   167  		}
   168  	}
   169  
   170  	for _, e := range list2 {
   171  		if _, ok := rl[e]; !ok {
   172  			r = append(r, e)
   173  		}
   174  	}
   175  
   176  	return l, r
   177  }
   178  
   179  // Pop returns an eent and removes it from the slice.
   180  func Pop[T comparable](list *[]T) (v T) {
   181  	l := len(*list)
   182  	if l == 0 {
   183  		return
   184  	}
   185  
   186  	v = (*list)[l-1]
   187  	*list = (*list)[:l-1]
   188  	return
   189  }
   190  
   191  // Shift returns an eent and removes it from the slice.
   192  func Shift[T comparable](list *[]T) (v T) {
   193  	l := len(*list)
   194  	if l == 0 {
   195  		return
   196  	}
   197  
   198  	v = (*list)[0]
   199  	*list = (*list)[1:]
   200  	return
   201  }