1

I would like to remove multiple elements from an array based on their indexes.

array=("a" "b" "c" "d")
indexes=(1 3)

Output should be

array=("a" "c")

I know how to remove an element from an array knowing the index of the element:

If $i is the index:

array=("${(@)array[1,$i-1]}" "${(@)array[$i+1,$#array]}")

But what if I have multiple elements to remove? If I loop over the array of indexes, once I have removed one element the other indexes won't correspond anymore to the elements to be removed. So how is it possible to do that?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Sulli
  • 763
  • 1
  • 11
  • 33

2 Answers2

3

Using BASH arrays you can do this easily:

# original array
array=("a" "b" "c" "d")

# indexes array
indexes=(1 3)

# loop through indexes array and delete from element array
for i in "${indexes[@]}"; do
   unset "array[$i]"
done

# check content of original array
declare -p array

declare -a array=([0]="a" [2]="c")

As per Chepner's comments below if OP wants an array of contiguous indices then loop through differential array and populate a new array

# result array
out=()

# loop through differential array and populate result
for i in "${array[@]}"; do
    out+=("$i")
done

declare -p out

declare -a out=([0]="a" [1]="c")
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • 1
    You don't actually need an associative array for `indexes`, since the keys are still integers. – chepner May 21 '18 at 17:38
  • 1
    This is definitely the simplest way to handle it; the only question is whether the resulting array should have contiguous indices or not. – chepner May 21 '18 at 17:46
  • I do need contiguous indices indeed, I didn't even know indices could be non-contiguous. So it's actually a lot of code, I thought there might be an easier way but apparently not – Sulli May 21 '18 at 18:25
0

Assuming indices is sorted, keep a counter of how many items you have already removed, and subtract that from each index in your loop.

count=0
for i in $indices; do
  c=$((i - count))
  array=("${(@)array[1,$c-1]}" "${(@)array[$c+1,$#array]}")
  count=$((count + 1))
done

In bash, the same approach looks like

count=0
for i in "${indices[@]}"; do
  c=$((i - count))
  array=( "${array[@]:0:c-1}" "${array[@]:c+1}" )
  count=$((count + 1))
done
chepner
  • 497,756
  • 71
  • 530
  • 681