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.