Skip to content

Commit

Permalink
arrays: add more util functions and tests for them - find_first, find…
Browse files Browse the repository at this point in the history
…_last, join_to_string (#18784)
  • Loading branch information
prashanth-hegde committed Jul 7, 2023
1 parent 7d6e15f commit e7e5a07
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 0 deletions.
52 changes: 52 additions & 0 deletions 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
Expand Down Expand Up @@ -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()
}
68 changes: 68 additions & 0 deletions vlib/arrays/arrays_test.v
Expand Up @@ -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'
}) == ''
}

0 comments on commit e7e5a07

Please sign in to comment.