Giving this array:
arr=(hello asd asd1 asd22 asd333)
I want to delete the a especific item by its value, for example asd. I did this:
IFS=' '
echo "${arr[@]/asd/}"
But it returns the following:
hello 1 22 333
So I did this function:
function remove_item() {
local item_search="$1"
shift
local arr_tmp=("${@}")
if [ ${#arr_tmp[@]} -eq 0 ]; then
return
fi
local index=0
for item in ${arr_tmp[@]}; do
if [ "$item" = "$item_search" ]; then
unset arr_tmp[$index]
break
fi
let index++
done
echo "${arr_tmp[*]}"
}
arr=(asd asd1 asd22 asd333)
remove_item 'asd' "${arr[@]}"
Prints the desired output:
hello asd1 asd22 asd333
But I have to use it with very long arrays, and I have to call it a lot of times. And its performance sucks.
Do you have any better alternative to do it? Any tip, trick, or advice will be appreciatted.
You could use a loop to iterate over the array and remove the element that matches the specified value:
for i in "${!arr[@]}"; do
[[ "${arr[i]}" == "asd" ]] && unset arr[i]
done
If you know that the array would have at most one matching element, you could even break out of the loop:
[[ "${arr[i]}" == "asd" ]] && unset arr[i] && break
|^^^^^^^^|
(this causes the loop to break
as soon as the element is found)
As an example:
$ arr=(asd asd1 asd22 asd333)
$ for i in "${!arr[@]}"; do [[ "${arr[i]}" == "asd" ]] && unset arr[i]; done
$ echo "${arr[@]}"
asd1 asd22 asd333
Probably @devnull's answer is fastest. But it might possibly be faster not to use a loop and instead let grep do the work. Its not very pretty though:
$ arr=(hello asd asd1 asd22 asd333)
$ remove="asd"
$ i=$(paste -d: <(printf "%s\n" "${!arr[@]}") <(printf "%s\n" "${arr[@]}") | grep -m1 -w -E "^[[:digit:]]+:${remove}$")
$ unset arr[${i%:*}]
$
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With