A website inspired by Last.fm that will keep track of your listening statistics
lastfm music statistics
at main 159 lines 4.0 kB view raw
1package enum 2 3import ( 4 "fmt" 5 "sort" 6) 7 8// A functional function that transforms items using a mapping function. 9func Map[T any, U any](items []T, fn func(T) U) []U { 10 var result []U 11 12 for _, item := range items { 13 result = append(result, fn(item)) 14 } 15 16 return result 17} 18 19// A functional function that reduces items to a single value using a reduction function. 20func Reduce[T any, U any](items []T, fn func(U, T) U, initial U) U { 21 result := initial 22 23 for _, item := range items { 24 result = fn(result, item) 25 } 26 27 return result 28} 29 30// A functional function that removes duplicate items based on a key function. The returned slice 31// will contain only the items that are unique according to the returned value of the key function. 32func UniqueBy[T any, K comparable](items []T, fn func(T) K) []T { 33 keys := make(map[K]struct{}) 34 var result []T 35 36 for _, item := range items { 37 key := fn(item) 38 if _, exists := keys[key]; exists { 39 continue 40 } 41 keys[key] = struct{}{} 42 result = append(result, item) 43 } 44 45 return result 46} 47 48// GroupBy groups elements of a slice by a key derived from each element. 49// The keyer function extracts the key from each element. 50func GroupBy[T any, K comparable](items []T, keyer func(T) K) map[K][]T { 51 groups := make(map[K][]T) 52 for _, item := range items { 53 key := keyer(item) 54 groups[key] = append(groups[key], item) 55 } 56 return groups 57} 58 59// GroupByWithValue groups elements of a slice by a key derived from each element, 60// and maps each element to a value derived from the element. 61func GroupByWithValue[T any, K comparable, V any](items []T, keyer func(T) K, valuer func(T) V) map[K][]V { 62 groups := make(map[K][]V) 63 for _, item := range items { 64 key := keyer(item) 65 value := valuer(item) 66 groups[key] = append(groups[key], value) 67 } 68 return groups 69} 70 71// Combine two slices into one map, where the first slice should have unique values that can be 72// used as keys. If the slices are not the same length, the extra values will be ignored 73func ZipMap[K comparable, T any](keys []K, values []T) map[K]T { 74 result := make(map[K]T) 75 for i, key := range keys { 76 if i < len(values) { 77 result[key] = values[i] 78 } 79 } 80 return result 81} 82 83// Combine two slices into one map, where the first slice should have unique values that can be 84// used as keys 85func ZipMapSafe[K comparable, T any](keys []K, values []T) (map[K]T, error) { 86 if len(keys) != len(values) { 87 return nil, fmt.Errorf("keys and values must have the same length") 88 } 89 90 result := make(map[K]T) 91 for i, key := range keys { 92 if i < len(values) { 93 result[key] = values[i] 94 } 95 } 96 return result, nil 97} 98 99// Create a slice of values from values inside the given slice that match the predicate 100func Filter[T any](items []T, predicate func(T) bool) []T { 101 var result []T 102 for _, item := range items { 103 if predicate(item) { 104 result = append(result, item) 105 } 106 } 107 return result 108} 109 110// Return the first value from the values inside the given slice that match the predicate, if no 111// values can be found, it will return an empty value with a false boolean 112func Find[T any](items []T, predicate func(T) bool) (T, bool) { 113 for _, item := range items { 114 if predicate(item) { 115 return item, true 116 } 117 } 118 var zero T 119 return zero, false 120} 121 122func Flatten[T any](items [][]T) []T { 123 var result []T 124 for _, item := range items { 125 result = append(result, item...) 126 } 127 return result 128} 129 130// OrderByKeys reorders items so that their keys appear in the same order as inputKeys. Items whose 131// key is not present in inputKeys are placed at the end (while preserving their relative order). 132func OrderByKeys[T any, K comparable](items []T, keys []K, keyFn func(T) K) []T { 133 if len(items) == 0 || len(keys) == 0 { 134 return items 135 } 136 137 pos := make(map[K]int, len(keys)) 138 for i, k := range keys { 139 pos[k] = i 140 } 141 142 const notFound = int(^uint(0) >> 1) // max int 143 144 sort.SliceStable(items, func(i, j int) bool { 145 pi, ok := pos[keyFn(items[i])] 146 if !ok { 147 pi = notFound 148 } 149 150 pj, ok := pos[keyFn(items[j])] 151 if !ok { 152 pj = notFound 153 } 154 155 return pi < pj 156 }) 157 158 return items 159}