什么是删除数组元素的最快方法?

3
给定以下数组:
arr=(hello asd asd1 asd22 asd333)

我想通过其值删除特定项,例如asd。我做了这个:

IFS=' '
echo "${arr[@]/asd/}"

但它返回以下内容:

hello 1 22 333

所以我写了这个函数:
function remove_item() {
    local item_search="$1"
    shift
    local arr_tmp=("${@}")

    if [ ${#arr_tmp[@]} -eq 0 ]; then
        return
    fi

    local index=0
    for item in ${arr_tmp[@]}; do
        if [ "$item" = "$item_search" ]; then
            unset arr_tmp[$index]
            break
        fi
        let index++
    done

    echo "${arr_tmp[*]}"
}

arr=(asd asd1 asd22 asd333)

remove_item 'asd' "${arr[@]}"

输出所需内容:

hello asd1 asd22 asd333

但是我必须在非常长的数组中使用它,并且我必须多次调用它。它的性能很差。

你有什么更好的替代方案吗?任何提示、技巧或建议都将不胜感激。


1
你的问题有点令人困惑,首先你说你想删除第一个项目(即按索引删除),但你编写的函数是按值删除的。那么目标是什么?如果是后者,如果你使用的是bash v>=4,你可以使用关联数组,这样就不必进行迭代了。 - Jakub Kotowski
抱歉,帖子已编辑!我想通过值来删除它。:) 谢谢 - mllamazares
你必须使用bash吗?也许其他编程语言在“非常长的数组”上会有更好的性能。 - j_random_hacker
“而且我必须多次调用它”,这是指您从一个数组中删除许多项,还是指您从许多数组中删除项? - ikegami
我怕这是不同的数组,伙计。 - mllamazares
显示剩余4条评论
2个回答

2
您可以使用循环遍历数组并移除与指定值匹配的元素:
for i in "${!arr[@]}"; do
  [[ "${arr[i]}" == "asd" ]] && unset arr[i]
done

如果您知道数组最多只有一个匹配元素,您甚至可以从循环中break出来:

  [[ "${arr[i]}" == "asd" ]] && unset arr[i] && break
                                            |^^^^^^^^|
                                             (this causes the loop to break
                                              as soon as the element is found)

作为一个例子:
$ arr=(asd asd1 asd22 asd333)
$ for i in "${!arr[@]}"; do [[ "${arr[i]}" == "asd" ]] && unset arr[i]; done
$ echo "${arr[@]}"
asd1 asd22 asd333

但是这段代码会一直循环到数组的结尾。而我的代码在第一个匹配时就停止了。如果我错了,请纠正我。 - mllamazares
@JohnDoe 如果你使用带有 break 的行,则它将在第一个匹配处中断。 - devnull
我知道。我的函数在第一次出现时失效,而你的函数没有。所以,我认为我的函数是最有效的,你不觉得吗? - mllamazares
@JohnDoe 我猜你可能没有理解 break 的部分。请参考上面的编辑,我已经添加了解释。如果你在循环中使用包含 break 的那一行,那么它会在找到元素后立即跳出循环。 - devnull
哈哈,抱歉。我没有注意到你已经编辑了帖子。谢谢你的所有帮助,@devnull。现在一切都清楚了。 :) - mllamazares
显示剩余2条评论

1

可能@devnull的答案是最快的。但是也许不使用循环,让grep来完成工作可能会更快。虽然这样做不太美观:

$ arr=(hello asd asd1 asd22 asd333)
$ remove="asd"
$ i=$(paste -d: <(printf "%s\n" "${!arr[@]}") <(printf "%s\n" "${arr[@]}") | grep -m1 -w -E "^[[:digit:]]+:${remove}$")
$ unset arr[${i%:*}]
$ 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接