arrays: add more modern array operation functions (#11488)
							parent
							
								
									9554470985
								
							
						
					
					
						commit
						0c0e28df6e
					
				|  | @ -162,8 +162,9 @@ pub struct WindowAttribute { | |||
| // get snapshots of the window of the given size sliding along array with the given step, where each snapshot is an array.
 | ||||
| // - `size` - snapshot size
 | ||||
| // - `step` - gap size between each snapshot, default is 1.
 | ||||
| // example A: arrays.window([1, 2, 3, 4], size: 2) => [[1, 2], [2, 3], [3, 4]]
 | ||||
| // example B: arrays.window([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], size: 3, step: 2) => [[1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9]]
 | ||||
| //
 | ||||
| // example A: `arrays.window([1, 2, 3, 4], size: 2)` => `[[1, 2], [2, 3], [3, 4]]`
 | ||||
| // example B: `arrays.window([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], size: 3, step: 2)` => `[[1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9]]`
 | ||||
| pub fn window<T>(list []T, attr WindowAttribute) [][]T { | ||||
| 	// allocate snapshot array
 | ||||
| 	mut windows := [][]T{cap: list.len - attr.size + 1} | ||||
|  | @ -180,3 +181,102 @@ pub fn window<T>(list []T, attr WindowAttribute) [][]T { | |||
| 
 | ||||
| 	return windows | ||||
| } | ||||
| 
 | ||||
| // sum up array, return nothing when array has no elements
 | ||||
| // NOTICE: currently V has bug that cannot make sum function takes custom struct with + operator overloaded.
 | ||||
| // which means you can only pass array of numbers for now.
 | ||||
| // Future work: Fix generic operator overloading detection issue.
 | ||||
| // usage: `arrays.sum<int>([1, 2, 3, 4, 5])?` => `15`
 | ||||
| pub fn sum<T>(list []T) ?T { | ||||
| 	if list.len == 0 { | ||||
| 		return error('Cannot sum up array of nothing.') | ||||
| 	} else { | ||||
| 		mut head := list[0] | ||||
| 
 | ||||
| 		for i, e in list { | ||||
| 			if i == 0 { | ||||
| 				continue | ||||
| 			} else { | ||||
| 				head += e | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return head | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // accumulates values with the first element and applying providing operation to current accumulator value and each elements.
 | ||||
| // if the array is empty, then returns error.
 | ||||
| // usage: `arrays.reduce([1, 2, 3, 4, 5], fn (t1 int, t2 int) int { return t1 * t2 })?` => `120`
 | ||||
| pub fn reduce<T>(list []T, reduce_op fn (t1 T, t2 T) T) ?T { | ||||
| 	if list.len == 0 { | ||||
| 		return error('Cannot reduce array of nothing.') | ||||
| 	} else { | ||||
| 		mut value := list[0] | ||||
| 
 | ||||
| 		for i, e in list { | ||||
| 			if i == 0 { | ||||
| 				continue | ||||
| 			} else { | ||||
| 				value = reduce_op(value, e) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return value | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // accumulates values with providing initial value and applying providing operation to current accumulator value and each elements.
 | ||||
| // usage: `arrays.fold<string, byte>(['H', 'e', 'l', 'l', 'o'], 0, fn (r int, t string) int { return r + t[0] })` => `149`
 | ||||
| pub fn fold<T, R>(list []T, init R, fold_op fn (r R, t T) R) R { | ||||
| 	mut value := init | ||||
| 
 | ||||
| 	for e in list { | ||||
| 		value = fold_op(value, e) | ||||
| 	} | ||||
| 
 | ||||
| 	return value | ||||
| } | ||||
| 
 | ||||
| // flattens n + 1 dimensional array into n dimensional array
 | ||||
| // usage: `arrays.flatten<int>([[1, 2, 3], [4, 5]])` => `[1, 2, 3, 4, 5]`
 | ||||
| pub fn flatten<T>(list [][]T) []T { | ||||
| 	// calculate required capacity
 | ||||
| 	mut required_size := 0 | ||||
| 
 | ||||
| 	for e1 in list { | ||||
| 		for _ in e1 { | ||||
| 			required_size += 1 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// allocate flattened array
 | ||||
| 	mut result := []T{cap: required_size} | ||||
| 
 | ||||
| 	for e1 in list { | ||||
| 		for e2 in e1 { | ||||
| 			result << e2 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return result | ||||
| } | ||||
| 
 | ||||
| // grouping list of elements with given key selector.
 | ||||
| // usage: `arrays.assort<int, string>(['H', 'el', 'lo'], fn (v string) int { return v.len })` => `{1: ['H'], 2: ['el', 'lo']}`
 | ||||
| pub fn group_by<K, V>(list []V, grouping_op fn (v V) K) map[K][]V { | ||||
| 	mut result := map[K][]V{} | ||||
| 
 | ||||
| 	for v in list { | ||||
| 		key := grouping_op(v) | ||||
| 
 | ||||
| 		// check if key exists, if not, then create a new array with matched value, otherwise append.
 | ||||
| 		if key in result { | ||||
| 			result[key] << v | ||||
| 		} else { | ||||
| 			result[key] = [v] | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return result | ||||
| } | ||||
|  |  | |||
|  | @ -106,3 +106,60 @@ fn test_window() { | |||
| 	assert window<int>(x, size: 3, step: 2) == [[1, 2, 3], [3, 4, 5]] | ||||
| 	assert window<int>([]int{}, size: 2) == [][]int{} | ||||
| } | ||||
| 
 | ||||
| fn test_sum() { | ||||
| 	x := [1, 2, 3, 4, 5] | ||||
| 
 | ||||
| 	assert sum<int>(x) or { 0 } == 15 | ||||
| 	assert sum<f64>([1.0, 2.5, 3.5, 4.0]) or { 0 } == 11.0 | ||||
| 	assert sum<int>([]int{}) or { 0 } == 0 | ||||
| } | ||||
| 
 | ||||
| fn test_reduce() { | ||||
| 	x := [1, 2, 3, 4, 5] | ||||
| 
 | ||||
| 	assert reduce<int>(x, fn (t1 int, t2 int) int { | ||||
| 		return t1 + t2 | ||||
| 	}) or { 0 } == 15 | ||||
| 	assert reduce<string>(['H', 'e', 'l', 'l', 'o'], fn (t1 string, t2 string) string { | ||||
| 		return t1 + t2 | ||||
| 	}) or { '' } == 'Hello' // For the sake please use array's join instead.
 | ||||
| 	assert reduce<int>([]int{}, fn (t1 int, t2 int) int { | ||||
| 		return 0 | ||||
| 	}) or { -1 } == -1 | ||||
| } | ||||
| 
 | ||||
| fn test_fold() { | ||||
| 	x := [1, 2, 3, 4, 5] | ||||
| 
 | ||||
| 	assert fold<int, int>(x, 5, fn (r int, t int) int { | ||||
| 		return r + t | ||||
| 	}) == 20 | ||||
| 	assert fold<string, int>(['H', 'e', 'l', 'l', 'l'], 0, fn (r int, t string) int { | ||||
| 		return r + t[0] | ||||
| 	}) == 497 | ||||
| 	assert fold<int, int>([]int{}, -1, fn (t1 int, t2 int) int { | ||||
| 		return 0 | ||||
| 	}) == -1 | ||||
| } | ||||
| 
 | ||||
| fn test_flatten() { | ||||
| 	x := [[1, 2, 3], [4, 5, 6]] | ||||
| 
 | ||||
| 	assert flatten<int>(x) == [1, 2, 3, 4, 5, 6] | ||||
| 	assert flatten<int>([[]int{}]) == [] | ||||
| } | ||||
| 
 | ||||
| fn test_group_by() { | ||||
| 	x := ['H', 'el', 'l', 'o '] | ||||
| 
 | ||||
| 	assert group_by<int, string>(x, fn (v string) int { | ||||
| 		return v.len | ||||
| 	}) == { | ||||
| 		1: ['H', 'l'] | ||||
| 		2: ['el', 'o '] | ||||
| 	} | ||||
| 	assert group_by<int, int>([]int{}, fn (v int) int { | ||||
| 		return 0 | ||||
| 	}) == map[int][]int{} | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue