1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
|
//
// This file is part of go-algorithms.
//
// Copyright 2024 Cristian Maglie. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
package f
import (
"runtime"
"sync"
"sync/atomic"
)
// Filter takes a slice of type []T and a Matcher[T]. It returns a newly
// allocated slice containing only those elements of the input slice that
// satisfy the matcher.
func Filter[T any](values []T, matcher Matcher[T]) []T {
var res []T
for _, x := range values {
if matcher(x) {
res = append(res, x)
}
}
return res
}
// Map applies the Mapper function to each element of the slice and returns
// a new slice with the results in the same order.
func Map[T, U any](values []T, mapper Mapper[T, U]) []U {
res := make([]U, len(values))
for i, x := range values {
res[i] = mapper(x)
}
return res
}
// ParallelMap applies the Mapper function to each element of the slice and returns
// a new slice with the results in the same order. This is executed among multilple
// goroutines in parallel. If jobs is specified it will indicate the maximum number
// of goroutines to be spawned.
func ParallelMap[T, U any](values []T, mapper Mapper[T, U], jobs ...int) []U {
res := make([]U, len(values))
var j int
if len(jobs) == 0 {
j = runtime.NumCPU()
} else if len(jobs) == 1 {
j = jobs[0]
} else {
panic("jobs must be a single value")
}
j = min(j, len(values))
var idx atomic.Int64
idx.Store(-1)
var wg sync.WaitGroup
wg.Add(j)
for count := 0; count < j; count++ {
go func() {
i := int(idx.Add(1))
for i < len(values) {
res[i] = mapper(values[i])
i = int(idx.Add(1))
}
wg.Done()
}()
}
wg.Wait()
return res
}
// Reduce applies the Reducer function to all elements of the input values
// and returns the result.
func Reduce[T any](values []T, reducer Reducer[T], initialValue ...T) T {
var result T
if len(initialValue) > 1 {
panic("initialValue must be a single value")
} else if len(initialValue) == 1 {
result = initialValue[0]
}
for _, v := range values {
result = reducer(result, v)
}
return result
}
// Equals return a Matcher that matches the given value
func Equals[T comparable](value T) Matcher[T] {
return func(x T) bool {
return x == value
}
}
// NotEquals return a Matcher that does not match the given value
func NotEquals[T comparable](value T) Matcher[T] {
return func(x T) bool {
return x != value
}
}
// Uniq return a copy of the input array with all duplicates removed
func Uniq[T comparable](in []T) []T {
have := map[T]bool{}
var out []T
for _, v := range in {
if have[v] {
continue
}
out = append(out, v)
have[v] = true
}
return out
}
// Count returns the number of elements in the input array that match the given matcher
func Count[T any](in []T, matcher Matcher[T]) int {
var count int
for _, v := range in {
if matcher(v) {
count++
}
}
return count
}
|