initial commit

This commit is contained in:
m.zare
2026-04-10 18:25:21 +03:30
commit 77ca6c34a3
263 changed files with 34470 additions and 0 deletions

26
pkg/array/aggregate.go Normal file
View File

@@ -0,0 +1,26 @@
package array
func Chunk[T interface{}](arr []T, chunkSize int) [][]T {
var chunkedArray [][]T
for i := 0; i < len(arr); i += chunkSize {
end := i + chunkSize
if end > len(arr) {
end = len(arr)
}
chunkedArray = append(chunkedArray, arr[i:end])
}
return chunkedArray
}
func Sum[T any, N Numbers](arr []T, selector func(val T) N) N {
var summed N
for i := 0; i < len(arr); i++ {
r := selector(arr[i])
summed += r
}
return summed
}

View File

@@ -0,0 +1,30 @@
package array
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestSum_WithNumberArray_ShouldBeAsExpected(t *testing.T) {
// Arrange
arr := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// Act
r := Sum(arr, func(val int) int {
return val
})
// Assert
const expected = 55
assert.True(t, r == expected)
}
func TestSum_WithStructArray_ShouldBeAsExpected(t *testing.T) {
// Arrange
arr := []struct{ d float64 }{{d: 0.1}, {d: 1.5}, {d: 0.4}, {d: 2.5}, {d: 5.521}}
// Act
r := Sum(arr, func(val struct{ d float64 }) float64 {
return val.d
})
// Assert
const expected = 10.021
assert.True(t, r == expected)
}

39
pkg/array/any.go Normal file
View File

@@ -0,0 +1,39 @@
package array
func All[T any](arr []T, predicate func(val T) bool) bool {
for i := 0; i < len(arr); i++ {
if !predicate(arr[i]) {
return false
}
}
return true
}
// Any returns true if any element in the array satisfies the predicate; otherwise, it returns false.
func Any[TIn any](arr []TIn, predicate func(val TIn) bool) bool {
for i := 0; i < len(arr); i++ {
if predicate(arr[i]) {
return true
}
}
return false
}
func AnyError[TIn any](arr []TIn, predicate func(val TIn) error) error {
for i := 0; i < len(arr); i++ {
if err := predicate(arr[i]); err != nil {
return err
}
}
return nil
}
// Contains checks if a slice contains a specific element.
func Contains[T comparable](slice []T, element T) bool {
for i := 0; i < len(slice); i++ {
if slice[i] == element {
return true
}
}
return false
}

75
pkg/array/diff.go Normal file
View File

@@ -0,0 +1,75 @@
package array
func Diff[T comparable](slice1, slice2 []T) []T {
var result []T
elementsMap := make(map[T]bool)
for _, v := range slice2 {
elementsMap[v] = true
}
for _, v := range slice1 {
if !elementsMap[v] {
result = append(result, v)
}
}
return result
}
func MapDiff[T comparable](slice1, slice2 []T) []T {
var result []T
arr1elementsMap := make(map[T]int)
for _, v := range slice1 {
arr1elementsMap[v] += 1
}
arr2elementsMap := make(map[T]int)
for _, v := range slice2 {
arr2elementsMap[v] += 1
}
for key, count1 := range arr1elementsMap {
if count2, ok := arr2elementsMap[key]; !ok || count2 != count1 {
result = append(result, key)
}
}
return result
}
// DiffByKeyAndValue returns the elements from slice1 that do not have
// corresponding elements in slice2 based on a key and a comparison function.
// T1 and T2 are the types of the elements in slice1 and slice2 respectively.
// K is the type of the key used for comparison.
func DiffByKeyAndValue[T1 any, T2 any, K comparable](
slice1 []T1,
slice2 []T2,
getKeyFromSlice1 func(T1) K,
getKeyFromSlice2 func(T2) K,
compare func(T1, T2) bool,
) []T1 {
// Create a map to index elements of slice2 by their keys
indexedSlice2 := make(map[K]T2)
for _, elementFromSlice2 := range slice2 {
key := getKeyFromSlice2(elementFromSlice2)
indexedSlice2[key] = elementFromSlice2
}
// Initialize a slice to hold the elements that are different
var differingElements []T1
// Iterate over slice1 and find elements that are not in slice2
for _, elementFromSlice1 := range slice1 {
key := getKeyFromSlice1(elementFromSlice1)
// Check if the key exists in the indexed slice2
if correspondingElementFromSlice2, exists := indexedSlice2[key]; !exists || !compare(elementFromSlice1, correspondingElementFromSlice2) {
// If it doesn't exist or the comparison fails, add to the result
differingElements = append(differingElements, elementFromSlice1)
}
}
return differingElements
}

5
pkg/array/empty.go Normal file
View File

@@ -0,0 +1,5 @@
package array
func IsEmpty[TIn any](arr []TIn) bool {
return arr == nil || len(arr) == 0
}

7
pkg/array/enumerator.go Normal file
View File

@@ -0,0 +1,7 @@
package array
type Enumerator[T any] interface {
Next() bool
Current() (*T, error)
Destroy() error
}

289
pkg/array/example_test.go Normal file
View File

@@ -0,0 +1,289 @@
package array_test
import (
"errors"
"fmt"
"sort"
"strings"
"base/pkg/array"
)
// Product represents a product in an base system
type Product struct {
ID int
Name string
Price float64
Category string
}
// ProductDTO is a data transfer object for Product
type ProductDTO struct {
ID int `json:"id"`
Name string `json:"name"`
PriceUSD string `json:"price_usd"`
Available bool `json:"available"`
}
// base represents a store's base
type base struct {
StoreID int
StoreName string
Products []Product
}
// Review represents a customer review
type Review struct {
ProductID int
Rating int
Comment string
}
func Example_map() {
// Create a slice of Product structs
products := []Product{
{ID: 1, Name: "Laptop", Price: 999.99, Category: "Electronics"},
{ID: 2, Name: "Headphones", Price: 99.99, Category: "Electronics"},
{ID: 3, Name: "Keyboard", Price: 49.99, Category: "Accessories"},
}
// Use Map to transform Product structs to ProductDTO structs
productDTOs := array.Map(products, func(p Product, i int) ProductDTO {
return ProductDTO{
ID: p.ID,
Name: p.Name,
PriceUSD: fmt.Sprintf("$%.2f", p.Price),
Available: p.Price > 0,
}
})
// Print the result
for _, dto := range productDTOs {
fmt.Printf("Product %d: %s - %s\n", dto.ID, dto.Name, dto.PriceUSD)
}
// Output:
// Product 1: Laptop - $999.99
// Product 2: Headphones - $99.99
// Product 3: Keyboard - $49.99
}
func Example_mapWithError() {
// Create a slice of Product structs
products := []Product{
{ID: 1, Name: "Laptop", Price: 999.99, Category: "Electronics"},
{ID: 2, Name: "Headphones", Price: 99.99, Category: "Electronics"},
{ID: 3, Name: "Keyboard", Price: 49.99, Category: "Accessories"},
}
// Use MapWithError to transform Product structs to discounted products,
// but only if the discount can be applied
discountedProducts, err := array.MapWithError(products, func(p Product, i int) (*Product, error) {
// For this example, we'll say we can't discount items under $50
if p.Price < 50.0 {
return nil, errors.New("cannot discount items under $50")
}
// Create a new product with 10% discount
discounted := p
discounted.Price = p.Price * 0.9
return &discounted, nil
})
// Check for errors
if err != nil {
fmt.Println("Error:", err)
} else {
// Print the result
for _, p := range discountedProducts {
fmt.Printf("Discounted %s: $%.2f\n", p.Name, p.Price)
}
}
// Try with products that all meet the criteria
expensiveProducts := []Product{
{ID: 1, Name: "Laptop", Price: 999.99, Category: "Electronics"},
{ID: 2, Name: "Smartphone", Price: 699.99, Category: "Electronics"},
}
discountedProducts, err = array.MapWithError(expensiveProducts, func(p Product, i int) (*Product, error) {
// All these products can be discounted
discounted := p
discounted.Price = p.Price * 0.9
return &discounted, nil
})
// Print the successful result
if err != nil {
fmt.Println("Error:", err)
} else {
for _, p := range discountedProducts {
fmt.Printf("Discounted %s: $%.2f\n", p.Name, p.Price)
}
}
// Output:
// Error: cannot discount items under $50
// Discounted Laptop: $899.99
// Discounted Smartphone: $629.99
}
func Example_mapD() {
// Create a map of store inventories
storeInventories := map[string]base{
"NY": {
StoreID: 1,
StoreName: "New York Store",
Products: []Product{
{ID: 1, Name: "Laptop", Price: 999.99, Category: "Electronics"},
{ID: 2, Name: "Headphones", Price: 99.99, Category: "Electronics"},
},
},
"LA": {
StoreID: 2,
StoreName: "Los Angeles Store",
Products: []Product{
{ID: 1, Name: "Laptop", Price: 1099.99, Category: "Electronics"},
{ID: 3, Name: "Keyboard", Price: 49.99, Category: "Accessories"},
},
},
}
// Use MapD to extract and format store information
storeInfos := array.MapD(storeInventories, func(inv base, location string) string {
return fmt.Sprintf("%s (ID: %d) - %s - %d products",
inv.StoreName, inv.StoreID, location, len(inv.Products))
})
// Sort the results for consistent output
sort.Strings(storeInfos)
// Print the result
for _, info := range storeInfos {
fmt.Println(info)
}
// Output:
// Los Angeles Store (ID: 2) - LA - 2 products
// New York Store (ID: 1) - NY - 2 products
}
func Example_forEach() {
// Create a slice of Product structs
products := []Product{
{ID: 1, Name: "Laptop", Price: 999.99, Category: "Electronics"},
{ID: 2, Name: "Headphones", Price: 99.99, Category: "Electronics"},
{ID: 3, Name: "Keyboard", Price: 49.99, Category: "Accessories"},
}
// Use ForEach to apply a 10% discount to all products
array.ForEach(products, func(p *Product, i int) {
p.Price = p.Price * 0.9
})
// Print the result
for _, p := range products {
fmt.Printf("%s: $%.2f\n", p.Name, p.Price)
}
// Output:
// Laptop: $899.99
// Headphones: $89.99
// Keyboard: $44.99
}
func Example_mapMany() {
// Create a slice of base structs
stores := []base{
{
StoreID: 1,
StoreName: "New York Store",
Products: []Product{
{ID: 1, Name: "Laptop", Price: 999.99, Category: "Electronics"},
{ID: 2, Name: "Headphones", Price: 99.99, Category: "Electronics"},
},
},
{
StoreID: 2,
StoreName: "Los Angeles Store",
Products: []Product{
{ID: 1, Name: "Laptop", Price: 1099.99, Category: "Electronics"},
{ID: 3, Name: "Keyboard", Price: 49.99, Category: "Accessories"},
},
},
}
// Use MapMany to flatten the store inventories into a list of product information
// but only include products priced over $100
productInfos := array.MapMany(stores,
func(store base) []Product {
return store.Products
},
func(store base, product Product) *string {
if product.Price < 100 {
return nil // Skip products under $100
}
info := fmt.Sprintf("%s - %s - $%.2f",
store.StoreName, product.Name, product.Price)
return &info
})
// Sort for consistent output
sort.Strings(productInfos)
// Print the result
for _, info := range productInfos {
fmt.Println(info)
}
// Output:
// Los Angeles Store - Laptop - $1099.99
// New York Store - Laptop - $999.99
}
func Example_mapManyD() {
// Create a map of store inventories
storeInventories := map[string]base{
"NY": {
StoreID: 1,
StoreName: "New York Store",
Products: []Product{
{ID: 1, Name: "Laptop", Price: 999.99, Category: "Electronics"},
{ID: 2, Name: "Headphones", Price: 99.99, Category: "Electronics"},
},
},
"LA": {
StoreID: 2,
StoreName: "Los Angeles Store",
Products: []Product{
{ID: 1, Name: "Laptop", Price: 1099.99, Category: "Electronics"},
{ID: 3, Name: "Keyboard", Price: 49.99, Category: "Accessories"},
},
},
}
// Use MapManyD to flatten the store inventories into a list of product names
productNames := array.MapManyD(storeInventories,
func(base base) []Product {
return base.Products
},
func(product Product) string {
return strings.ToUpper(product.Name)
})
// Sort for consistent output
sort.Strings(productNames)
// Print the result
fmt.Println("All product names (uppercase):")
for _, name := range productNames {
fmt.Println(name)
}
// Output:
// All product names (uppercase):
// HEADPHONES
// KEYBOARD
// LAPTOP
// LAPTOP
}

20
pkg/array/find.go Normal file
View File

@@ -0,0 +1,20 @@
package array
func Find[TIn any](arr []TIn, predicate func(val TIn) bool) *TIn {
for i := range arr {
if predicate(arr[i]) {
return &arr[i]
}
}
return nil
}
func Filter[TIn any](arr []TIn, predicate func(val *TIn) bool) []TIn {
var r []TIn
for i := range arr {
if predicate(&arr[i]) {
r = append(r, arr[i])
}
}
return r
}

188
pkg/array/map.go Normal file
View File

@@ -0,0 +1,188 @@
package array
// MapWithError transforms each element in the input slice to a new type, with error handling.
//
// It applies the selector function to each element in the input slice and its index.
// If the selector function returns an error for any element, the function immediately
// returns that error and a nil slice. Otherwise, it returns a new slice containing
// all transformed elements and nil error.
//
// Generic parameters:
// - TIn: The type of elements in the input slice
// - TOut: The type of elements in the output slice
//
// Parameters:
// - arr: The input slice to transform
// - selector: A function that takes an element and its index, returning a pointer to
// the transformed value and an error
//
// Returns:
// - A slice of transformed elements
// - An error if the transformation failed for any element
func MapWithError[TIn any, TOut any](arr []TIn, selector func(val TIn, index int) (*TOut, error)) ([]TOut, error) {
var output []TOut
for i := range arr {
out, err := selector(arr[i], i)
if err != nil {
return nil, err
}
output = append(output, *out)
}
return output, nil
}
// Map transforms each element in the input slice to a new type.
//
// It applies the selector function to each element in the input slice and its index,
// returning a new slice containing all transformed elements.
//
// Generic parameters:
// - TIn: The type of elements in the input slice
// - TOut: The type of elements in the output slice
//
// Parameters:
// - arr: The input slice to transform
// - selector: A function that takes an element and its index, returning the transformed value
//
// Returns:
// - A slice of transformed elements
func Map[TIn any, TOut any](arr []TIn, selector func(val TIn, index int) TOut) []TOut {
var output []TOut
for i := range arr {
out := selector(arr[i], i)
output = append(output, out)
}
return output
}
// MapD transforms each value in a map to an element in a slice.
//
// It applies the selector function to each value and key in the input map,
// returning a slice containing all transformed values.
//
// Generic parameters:
// - TKey: The type of keys in the input map (must be comparable)
// - TIn: The type of values in the input map
// - TOut: The type of elements in the output slice
//
// Parameters:
// - m: The input map to transform
// - selector: A function that takes a value and its key, returning the transformed value
//
// Returns:
// - A slice of transformed values
func MapD[TKey comparable, TIn any, TOut any](m map[TKey]TIn, selector func(val TIn, key TKey) TOut) []TOut {
var output []TOut
for i := range m {
out := selector(m[i], i)
output = append(output, out)
}
return output
}
// ForEach applies a function to each element in the input slice.
//
// Unlike Map, ForEach modifies elements in place by providing a pointer to each element.
// This function does not return a new slice.
//
// Generic parameters:
// - TIn: The type of elements in the input slice
//
// Parameters:
// - arr: The input slice whose elements will be processed
// - selector: A function that takes a pointer to an element and its index
func ForEach[TIn any](arr []TIn, selector func(val *TIn, index int)) {
for i := 0; i < len(arr); i++ {
selector(&arr[i], i)
}
}
// MapMany transforms and flattens a nested collection structure.
//
// It first applies the collectionSelector to each element in the input slice to produce
// an inner collection. Then it applies the resultSelector to each inner element along with
// the original element, flattening the result into a single output slice. If resultSelector
// returns nil for any element, that element is skipped in the output.
//
// Generic parameters:
// - TIn: The type of elements in the input slice
// - TC: The type of elements in the inner collections
// - TOut: The type of elements in the output slice
//
// Parameters:
// - m: The input slice to transform
// - collectionSelector: A function that produces an inner collection from each input element
// - resultSelector: A function that transforms each inner element along with its parent element
//
// Returns:
// - A flattened slice of transformed elements
func MapMany[TIn any, TC any, TOut any](m []TIn, collectionSelector func(TIn) []TC, resultSelector func(TIn, TC) *TOut) []TOut {
var output []TOut
for i := range m {
out := collectionSelector(m[i])
for _, v := range out {
result := resultSelector(m[i], v)
if result == nil {
continue
}
output = append(output, *result)
}
}
return output
}
// MapManyD transforms and flattens values from a map.
//
// It first applies the collectionSelector to each value in the input map to produce
// an inner collection. Then it applies the resultSelector to each inner element,
// flattening the results into a single output slice.
//
// Generic parameters:
// - TKey: The type of keys in the input map (must be comparable)
// - TIn: The type of values in the input map
// - TC: The type of elements in the inner collections
// - TOut: The type of elements in the output slice
//
// Parameters:
// - m: The input map to transform
// - collectionSelector: A function that produces an inner collection from each input value
// - resultSelector: A function that transforms each inner element
//
// Returns:
// - A flattened slice of transformed elements
func MapManyD[TKey comparable, TIn any, TC any, TOut any](m map[TKey]TIn, collectionSelector func(TIn) []TC, resultSelector func(TC) TOut) []TOut {
var output []TOut
for i := range m {
out := collectionSelector(m[i])
for _, v := range out {
output = append(output, resultSelector(v))
}
}
return output
}
// ToMap converts a slice of items into a map using the provided key and value selectors.
// TKey is the type of the keys in the resulting map, TIn is the type of items in the input slice,
// and TOut is the type of the values in the resulting map.
func ToMap[TKey comparable, TIn any, TOut any](
items []TIn,
keySelector func(TIn) TKey,
valueSelector func(TIn) TOut,
) map[TKey]TOut {
// Create a map with an initial capacity equal to the length of the input slice
resultMap := make(map[TKey]TOut, len(items))
// Iterate through each item in the slice
for _, item := range items {
// Get the key and value using the provided selectors
key := keySelector(item)
value := valueSelector(item)
// Store the key-value pair in the result map
resultMap[key] = value
}
return resultMap
}

362
pkg/array/map_test.go Normal file
View File

@@ -0,0 +1,362 @@
package array
import (
"errors"
"reflect"
"testing"
)
func TestMapWithError(t *testing.T) {
t.Run("success case", func(t *testing.T) {
// Arrange
input := []int{1, 2, 3}
expected := []string{"1", "2", "3"}
// Act
result, err := MapWithError(input, func(val int, index int) (*string, error) {
str := string(rune(val + '0'))
return &str, nil
})
// Assert
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if !reflect.DeepEqual(result, expected) {
t.Errorf("Expected %v, got %v", expected, result)
}
})
t.Run("error case", func(t *testing.T) {
// Arrange
input := []int{1, 2, 3}
testErr := errors.New("test error")
// Act
result, err := MapWithError(input, func(val int, index int) (*string, error) {
if val == 2 {
return nil, testErr
}
str := string(rune(val + '0'))
return &str, nil
})
// Assert
if err != testErr {
t.Errorf("Expected error %v, got %v", testErr, err)
}
if result != nil {
t.Errorf("Expected nil result, got %v", result)
}
})
t.Run("empty array", func(t *testing.T) {
// Arrange
var input []int
// Act
result, err := MapWithError(input, func(val int, index int) (*string, error) {
str := string(rune(val + '0'))
return &str, nil
})
// Assert
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if len(result) != 0 {
t.Errorf("Expected empty result, got %v", result)
}
})
}
func TestMap(t *testing.T) {
t.Run("basic transformation", func(t *testing.T) {
// Arrange
input := []int{1, 2, 3}
expected := []string{"1", "2", "3"}
// Act
result := Map(input, func(val int, index int) string {
return string(rune(val + '0'))
})
// Assert
if !reflect.DeepEqual(result, expected) {
t.Errorf("Expected %v, got %v", expected, result)
}
})
t.Run("use index in transformation", func(t *testing.T) {
// Arrange
input := []string{"a", "b", "c"}
expected := []string{"a0", "b1", "c2"}
// Act
result := Map(input, func(val string, index int) string {
return val + string(rune(index+'0'))
})
// Assert
if !reflect.DeepEqual(result, expected) {
t.Errorf("Expected %v, got %v", expected, result)
}
})
t.Run("empty array", func(t *testing.T) {
// Arrange
var input []int
// Act
result := Map(input, func(val int, index int) string {
return string(rune(val + '0'))
})
// Assert
if len(result) != 0 {
t.Errorf("Expected empty result, got %v", result)
}
})
}
func TestMapD(t *testing.T) {
t.Run("map dictionary to array", func(t *testing.T) {
// Arrange
input := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
// Act
result := MapD(input, func(val int, key string) string {
return key + string(rune(val+'0'))
})
// Assert
// Since map iteration order is not guaranteed, we check that all expected elements are in the result
expectedElements := []string{"a1", "b2", "c3"}
if len(result) != len(expectedElements) {
t.Errorf("Expected result length %d, got %d", len(expectedElements), len(result))
}
resultMap := make(map[string]bool)
for _, v := range result {
resultMap[v] = true
}
for _, expected := range expectedElements {
if !resultMap[expected] {
t.Errorf("Expected result to contain %s, but it doesn't", expected)
}
}
})
t.Run("empty map", func(t *testing.T) {
// Arrange
input := map[string]int{}
// Act
result := MapD(input, func(val int, key string) string {
return key + string(rune(val+'0'))
})
// Assert
if len(result) != 0 {
t.Errorf("Expected empty result, got %v", result)
}
})
}
func TestForEach(t *testing.T) {
t.Run("modify array in place", func(t *testing.T) {
// Arrange
input := []int{1, 2, 3}
expected := []int{2, 3, 4}
// Act
ForEach(input, func(val *int, index int) {
*val += 1
})
// Assert
if !reflect.DeepEqual(input, expected) {
t.Errorf("Expected %v, got %v", expected, input)
}
})
t.Run("use index in modification", func(t *testing.T) {
// Arrange
input := []int{1, 2, 3}
expected := []int{1, 3, 5}
// Act
ForEach(input, func(val *int, index int) {
*val = *val + index
})
// Assert
if !reflect.DeepEqual(input, expected) {
t.Errorf("Expected %v, got %v", expected, input)
}
})
t.Run("empty array", func(t *testing.T) {
// Arrange
var input []int
callCount := 0
// Act
ForEach(input, func(val *int, index int) {
callCount++
})
// Assert
if callCount != 0 {
t.Errorf("Expected callback not to be called, but it was called %d times", callCount)
}
})
}
func TestMapMany(t *testing.T) {
t.Run("basic flat mapping", func(t *testing.T) {
// Arrange
input := []int{1, 2}
expected := []string{"1a", "1b", "2a", "2b"}
// Act
result := MapMany(input,
func(i int) []string {
return []string{"a", "b"}
},
func(i int, s string) *string {
res := string(rune(i+'0')) + s
return &res
})
// Assert
if !reflect.DeepEqual(result, expected) {
t.Errorf("Expected %v, got %v", expected, result)
}
})
t.Run("with nil results", func(t *testing.T) {
// Arrange
input := []int{1, 2, 3}
expected := []string{"1a", "2a", "3a"}
// Act
result := MapMany(input,
func(i int) []string {
return []string{"a", "b"}
},
func(i int, s string) *string {
if s == "b" {
return nil
}
res := string(rune(i+'0')) + s
return &res
})
// Assert
if !reflect.DeepEqual(result, expected) {
t.Errorf("Expected %v, got %v", expected, result)
}
})
t.Run("empty input array", func(t *testing.T) {
// Arrange
var input []int
// Act
result := MapMany(input,
func(i int) []string {
return []string{"a", "b"}
},
func(i int, s string) *string {
res := string(rune(i+'0')) + s
return &res
})
// Assert
if len(result) != 0 {
t.Errorf("Expected empty result, got %v", result)
}
})
}
func TestMapManyD(t *testing.T) {
t.Run("map dictionary to flattened array", func(t *testing.T) {
// Arrange
input := map[string]int{
"a": 1,
"b": 2,
}
// Act
result := MapManyD(input,
func(val int) []string {
return []string{"x", "y"}
},
func(s string) string {
return s + "z"
})
// Assert
// Since map iteration order is not guaranteed, we check that all expected elements are in the result
expectedElements := []string{"xz", "yz", "xz", "yz"}
if len(result) != len(expectedElements) {
t.Errorf("Expected result length %d, got %d", len(expectedElements), len(result))
}
resultMap := make(map[string]int)
for _, v := range result {
resultMap[v]++
}
if resultMap["xz"] != 2 || resultMap["yz"] != 2 {
t.Errorf("Expected result to contain 2 of each 'xz' and 'yz', got %v", resultMap)
}
})
t.Run("empty inner collection", func(t *testing.T) {
// Arrange
input := map[string]int{
"a": 1,
"b": 2,
}
// Act
result := MapManyD(input,
func(val int) []string {
return []string{}
},
func(s string) string {
return s + "z"
})
// Assert
if len(result) != 0 {
t.Errorf("Expected empty result, got %v", result)
}
})
t.Run("empty input map", func(t *testing.T) {
// Arrange
input := map[string]int{}
// Act
result := MapManyD(input,
func(val int) []string {
return []string{"x", "y"}
},
func(s string) string {
return s + "z"
})
// Assert
if len(result) != 0 {
t.Errorf("Expected empty result, got %v", result)
}
})
}

72
pkg/array/sort.go Normal file
View File

@@ -0,0 +1,72 @@
package array
import "sort"
type Numbers interface {
int | int8 | int16 | int32 | int64 | float32 | float64
}
// BubbleSort
// Deprecated; use sort package
func BubbleSort[T any, N Numbers](arr []T, selector func(val T) N) {
n := len(arr)
for i := 0; i < n-1; i++ {
for j := 0; j < n-i-1; j++ {
c := selector(arr[j])
n := selector(arr[j+1])
if c > n {
// swap arr[j] and arr[j+1]
arr[j], arr[j+1] = arr[j+1], arr[j]
}
}
}
}
// BubbleSortDesc
// Deprecated; use sort package
func BubbleSortDesc[T any](arr []T, selector func(val T) float64) {
n := len(arr)
for i := 0; i < n-1; i++ {
for j := 0; j < n-i-1; j++ {
c := selector(arr[j])
n := selector(arr[j+1])
if c < n { // Change comparison operator to less than
// swap arr[j] and arr[j+1]
arr[j], arr[j+1] = arr[j+1], arr[j]
}
}
}
}
func FindDifference[T Numbers](primary, secondary []T) []T {
m := make(map[T]struct{})
for _, num := range secondary {
m[num] = struct{}{}
}
var diff []T
for _, num := range primary {
if _, found := m[num]; !found {
diff = append(diff, num)
}
}
return diff
}
func SortIntMap[T any](m map[int]T) []T {
result := make([]T, 0, len(m))
keys := make([]int, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Ints(keys)
for _, k := range keys {
result = append(result, m[k])
}
return result
}