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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.