diff --git a/vlib/arrays/arrays.v b/vlib/arrays/arrays.v index aedf8d87b404af..6fc84d8c2d8e0d 100644 --- a/vlib/arrays/arrays.v +++ b/vlib/arrays/arrays.v @@ -1,5 +1,7 @@ module arrays +import strings + // Common arrays functions: // - min / max - return the value of the minumum / maximum // - idx_min / idx_max - return the index of the first minumum / maximum @@ -664,3 +666,53 @@ pub fn carray_to_varray[T](c_array_data voidptr, items int) []T { unsafe { vmemcpy(v_array.data, c_array_data, total_size) } return v_array } + +// find_first returns the first element that matches the given predicate +// returns `none`, if there is no match found +// Example: arrays.find_first([1, 2, 3, 4, 5], fn (arr int) bool { arr == 3}) // => 3 +pub fn find_first[T](array []T, predicate fn (elem T) bool) ?T { + if array.len == 0 { + return none + } + for item in array { + if predicate(item) { + return item + } + } + return none +} + +// find_last returns the last element that matches the given predicate +// returns `none`, if there is no match found +// Example: arrays.find_last([1, 2, 3, 4, 5], fn (arr int) bool { arr == 3}) // => 3 +pub fn find_last[T](array []T, predicate fn (elem T) bool) ?T { + if array.len == 0 { + return none + } + for idx := array.len - 1; idx >= 0; idx-- { + item := array[idx] + if predicate(item) { + return item + } + } + return none +} + +// join_to_string takes in a custom transform function and joins all elements into a string with +// the specified separator +[manualfree] +pub fn join_to_string[T](array []T, separator string, transform fn (elem T) string) string { + mut sb := strings.new_builder(array.len * 2) + defer { + unsafe { sb.free() } + } + for i, item in array { + x := transform(item) + sb.write_string(x) + unsafe { x.free() } + if i < array.len - 1 { + sb.write_string(separator) + } + } + return sb.str() +} diff --git a/vlib/arrays/arrays_test.v b/vlib/arrays/arrays_test.v index 6180e505db8586..70c8ecba1a1c7e 100644 --- a/vlib/arrays/arrays_test.v +++ b/vlib/arrays/arrays_test.v @@ -404,3 +404,71 @@ fn test_map_of_counts() { assert map_of_counts(['abc', 'def', 'abc']) == {'abc': 2, 'def': 1} // vfmt on } + +struct FindTest { + name string + age int +} + +const test_structs = [FindTest{'one', 1}, FindTest{'two', 2}, + FindTest{'three', 3}, FindTest{'one', 4}] + +fn test_find_first() { + // element in array + a := [1, 2, 3, 4, 5] + assert find_first[int](a, fn (arr int) bool { + return arr == 3 + })? == 3, 'find element couldnt find the right element' + + // find struct + find_by_name := find_first(arrays.test_structs, fn (arr FindTest) bool { + return arr.name == 'one' + })? + assert find_by_name == FindTest{'one', 1} + + // not found + if _ := find_first(arrays.test_structs, fn (arr FindTest) bool { + return arr.name == 'nothing' + }) + { + assert false + } else { + assert true + } +} + +fn test_find_last() { + // // element in array + a := [1, 2, 3, 4, 5] + assert find_last[int](a, fn (arr int) bool { + return arr == 3 + })? == 3, 'find element couldnt find the right element' + + // find struct + find_by_name := find_last(arrays.test_structs, fn (arr FindTest) bool { + return arr.name == 'one' + })? + assert find_by_name == FindTest{'one', 4} + + // not found + if _ := find_last(arrays.test_structs, fn (arr FindTest) bool { + return arr.name == 'nothing' + }) + { + assert false + } else { + assert true + } +} + +fn test_join_to_string() { + assert join_to_string[FindTest](arrays.test_structs, ':', fn (it FindTest) string { + return it.name + }) == 'one:two:three:one' + assert join_to_string[FindTest](arrays.test_structs, '', fn (it FindTest) string { + return it.name + }) == 'onetwothreeone' + assert join_to_string[int]([]int{}, ':', fn (it int) string { + return '1' + }) == '' +}