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?

5
  • Don't know about bash, but in other languages I'd loop backwards. Commented May 21, 2018 at 17:04
  • 1
    The example you show is zsh, not bash. Commented May 21, 2018 at 17:21
  • @chepner so I don't really know how to do that in pure bash :) or I've read it's complicated stackoverflow.com/questions/16860877/… Commented May 21, 2018 at 17:32
  • Are you trying to do it in bash? Commented May 21, 2018 at 17:33
  • @chepner yes I am! I saw your edit Commented May 21, 2018 at 17:38

2 Answers 2

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")
Sign up to request clarification or add additional context in comments.

3 Comments

You don't actually need an associative array for indexes, since the keys are still integers.
This is definitely the simplest way to handle it; the only question is whether the resulting array should have contiguous indices or not.
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
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

1 Comment

c-1 is going to be negative on the first round if index=0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.