Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 60 additions & 4 deletions ar.bash
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ ar::insert() {


## @fn ar::index()
## @brief Return the index of the first item in array whose needle is equal to the given value.
## @brief Return the index of the first item in array equal to the given value.
## @detail Like Python's list.index(x[, start[, end]])
## Usage: ar::index arrayname needle [start [end]]
ar::index() {
Expand Down Expand Up @@ -304,8 +304,8 @@ ar::reverse() {
## @param arr_set The array to write the result into
ar::set() {
local -n arr="$1"
local -A assoc
local -n arr_set="$2"
local -A assoc
for val in "${arr[@]}"; do
assoc[$val]=1
done
Expand Down Expand Up @@ -351,12 +351,12 @@ ar::union() {
}


## @fn ar::punion()
## @fn ar::print_union()
## @brief Print the union of two arrays
## @detail Can be captured as an array with res=($(punion arr1 arr2))
## @param arr1 The first array
## @param arr2 The second array
ar::punion() {
ar::print_union() {
local -n arr1="$1"
local -n arr2="$2"
local -A union_assoc
Expand Down Expand Up @@ -399,6 +399,62 @@ ar::intersection() {
intersect_arr=("${!intersect_assoc[@]}")
}

## @fn ar::difference
## @brief Write the difference between two sets to a third var
## @detail Write elements that are in the first set but not the second.
## @param arr1 The first array name
## @param arr2 The second array name
## @params difference_arr The array name to write the result to
ar::difference() {
local -n arr1="$1"
local -n arr2="$2"
local -n difference_arr="$3"
local -A assoc2
local -A diff_assoc
for val in "${arr2[@]}"; do
assoc2["$val"]=1
done
for val in "${arr1[@]}"; do
if [[ ! -v assoc2["$val"] ]]; then
diff_assoc["$val"]=1
fi
done
difference_arr=("${!diff_assoc[@]}")
}

## @fn ar::symmetric_difference
## @brief Write the symmetric difference between two sets to a third var
## @detail Write elements are in either set but not their intersection
## @param arr1 The first array name
## @param arr2 The second array name
## @params difference_arr The array name to write the result to
ar::symmetric_difference() {
local -n arr1="$1"
local -n arr2="$2"
local -n symmetric_diff_arr="$3"
local -A assoc1 assoc2 symmetric_diff_assoc

for val in "${arr1[@]}"; do
assoc1["$val"]=1
done
for val in "${arr2[@]}"; do
assoc2["$val"]=1
done

# Find elements in arr1 but not arr2
for val in "${arr1[@]}"; do
if [[ ! -v assoc2["$val"] ]]; then
symmetric_diff_assoc["$val"]=1
fi
done
# Find elements in arr2 but not arr1
for val in "${arr2[@]}"; do
if [[ ! -v assoc1["$val"] ]]; then
symmetric_diff_assoc["$val"]=1
fi
done
symmetric_diff_arr=("${!symmetric_diff_assoc[@]}")
}

## @fn array_to_string
## @brief Turn an array into a string with seperator
Expand Down
83 changes: 82 additions & 1 deletion tests/test_ar.bats
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ setup() {
done
}

@test "ar::pop removes and returns an element from the end of the array" {
ar::pop _starting_array
[[ "${#_starting_array[@]}" == 2 ]]
}

@test "ar::index returns the index for the first occurence of value" {
local i
i="$(ar::index _starting_array sausage)"
Expand All @@ -54,14 +59,38 @@ setup() {
[[ $status -eq 2 ]]
}

@test "ar::extend appends items from the second array to the first array" {
local _second_array=(onions celery garlic)
ar::extend _starting_array _second_array
[[ "${_starting_array[*]}" == "rice beans sausage onions celery garlic" ]]
}

@test "ar::remove removes the first occurence of value from the array" {
ar::remove _starting_array rice
[[ "${_starting_array[*]}" == "beans sausage" ]]
}

@test "ar::remove fails with non-zero rc if value does not exist" {
run ar::remove _starting_array beef
[[ $status -eq 1 ]]
assert_failure
}

@test "ar::count returns the number of times value appears in array" {
run ar::count _starting_array "rice"
assert_success
assert_output "1"

local _another_array=(rice beans rice sausage)
run ar::count _another_array "rice"
assert_success
assert_output "2"
}

@test "ar::reverse reverses an array in-place" {
local _starting_array=(rice beans sausage)
local _expected_reversed_array=(sausage beans rice)
ar::reverse _starting_array
assert_equal "${_starting_array[*]}" "${_expected_reversed_array[*]}"
}

@test "ar::set turns an array into a set array" {
Expand All @@ -77,3 +106,55 @@ setup() {
ar::in_set expected_arr "${set_arr[i]}"
done
}

@test "ar::union writes the union of two sets to a third var" {
local -a first_arr=(rice beans sausage)
local -a second_arr=(beef onions)
local -i first_len="${#first_arr[@]}"
local -i second_len="${#second_arr[@]}"
local -i combined_len=$(( first_len + second_len ))
local -i i
local -a union_arr
ar::union first_arr second_arr union_arr
assert_equal "$combined_len" 5
for ((i=0; i < first_len; i++)); do
ar::in_set union_arr "${first_arr[i]}"
[[ $status -eq 0 ]]
done
for ((i=0; i < second_len; i++)); do
ar::in_set union_arr "${second_arr[i]}"
[[ $status -eq 0 ]]
done
}

@test "ar::intersection writes the intersection of two sets to a third var" {
local -a first_arr=(rice beans sausage)
local -a second_arr=(rice beef onions)
local -a intersection_arr
ar::intersection first_arr second_arr intersection_arr
assert_equal "${intersection_arr[0]}" "rice"
}

@test "ar::difference writes the set difference of two sets to a third var" {
local -a first_arr=(rice beans sausage)
local -a second_arr=(rice beef onions)
local -a expected_diff=(beans sausage)
local -a diff_arr
ar::difference first_arr second_arr diff_arr
assert_equal "${diff_arr[*]}" "${expected_diff[*]}"
}

@test "ar::symmetric_difference writes the symmetric set difference of two sets to a third var" {
local -a first_arr=(rice beans sausage)
local -a second_arr=(rice beef onions)
local -a expected_diff=(beans sausage beef onions)
local -a diff_arr
ar::symmetric_difference first_arr second_arr diff_arr
# Order shouldn't matter
local -i expected_len="${#expected_diff[@]}"
local -i actual_len="${#diff_arr[@]}"
assert_equal "$expected_len" "$actual_len"
for ((i=0; i < expected_len; i++)); do
ar::in_set diff_arr "${expected_diff[i]}"
done
}