【问题标题】:Remove multiple elements from array based on index根据索引从数组中删除多个元素
【发布时间】:2018-10-31 09:15:04
【问题描述】:

我想根据索引从数组中删除多个元素。

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

输出应该是

array=("a" "c")

我知道如何从知道元素索引的数组中删除元素:

如果 $i 是索引:

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

但是如果我要删除多个元素怎么办?如果我遍历索引数组,一旦我删除了一个元素,其他索引将不再对应于要删除的元素。那怎么可能呢?

【问题讨论】:

  • 不了解 bash,但在其他语言中我会向后循环。
  • 你展示的例子是zsh,而不是bash
  • @chepner 所以我真的不知道如何在纯 bash 中做到这一点 :) 或者我读过它很复杂 stackoverflow.com/questions/16860877/…
  • 你是否尝试bash做这件事?
  • @chepner 是的,我是!我看到了你的编辑

标签: bash


【解决方案1】:

使用 BASH 数组可以轻松做到这一点:

# 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")

根据下面 Chepner 的 cmets,如果 OP 想要一个连续索引数组,则循环遍历差分数组并填充一个新数组

# 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")

【讨论】:

  • 您实际上并不需要 indexes 的关联数组,因为键仍然是整数。
  • 这绝对是最简单的处理方式;唯一的问题是结果数组是否应该有连续的索引。
  • 我确实需要连续索引,我什至不知道索引可能是不连续的。所以实际上代码很多,我认为可能有更简单的方法,但显然不是
【解决方案2】:

假设 indices 已排序,请记下您已删除的项目数量,并从循环中的每个索引中减去该值。

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

bash,同样的做法看起来像

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

【讨论】:

  • c-1 在第一轮如果 index=0 会是负数