从数组中删除条目

37

我想要做像这样的事情:

foo=(a b c)
foo-=b
echo $foo # should output "a c"

如何从数组中删除一个元素? foo-=b 无法实现此功能。

删除操作应该不受元素位置的限制。

5个回答

43

要删除元素编号为$i的元素: a=("${(@)a[1,$i-1]}" "${(@)a[$i+1,$#a]}")

(简化的语法a=($a[1,$i-1] $a[$i+1,-1])也可以删除空元素。)

添加:

要删除任何匹配的b元素: a=("${(@)a:#b}")
:#是用于删除匹配的符号,""(@)可使其在数组中正确操作即使它们包含空元素。


看看我的答案,有一个更简单的解决方案。 - mislav
由于数组是基于0的索引,所以a=("${(@)a[1,...应该是a=("${(@)a[0,(从0开始)。 - phil294
@Blauhirn Zsh的数组默认是以1为基础(它们可以是以0为基础,但您必须激活ksh兼容模式)。 - Gilles 'SO- stop being evil'
@Timo 一个并不随着另一个而来。${a:#}被解析为${VARIABLE:#PATTERN}参数扩展结构,而不是${VARIABLE:INDEX}结构。此外,${a:$#a}不会删除最后一个元素,它将从最后一个元素之后开始取一个切片,因此它将是一个空数组。 - Gilles 'SO- stop being evil'
这不会删除最后一个元素。 - piojo
显示剩余5条评论

42

如果您希望删除所有出现的内容,则Gilles第二个答案是正确的,但它会完全重新分配数组,并且无法解决您仅希望删除单个条目的情况,而不管重复项如何。在zsh中,有一种方法可以从正常的数组中删除元素,而无需重新分配整个数组:

假设有以下数组:

array=(abc def ghi)

以下代码将返回第一个匹配项的索引位置def:

${array[(i)def]}

下面的格式可以用来从数组中删除任何给定的索引值(在此示例中为元素索引2),而无需重新分配整个数组:

array[2]=()

因此,要删除值def,我们将两个值组合:

array[$array[(i)def]]=()

对于单个元素的删除,这种方法更为简洁,因为没有显式的数组重新分配(更加简洁,避免了任何潜在的副作用,例如意外删除空项、引号格式问题等)。但是,Gilles的解决方案在很大程度上是等效的,并且具有多个匹配项删除的优势,如果这正是您想要的。使用他的方法和这种方法,您将拥有一个完整的工具集,用于标准数组元素的删除。


同样相关的是:使用(I)来删除最后一个匹配项而不是第一个。在i/I标志后添加e以获得精确匹配;在这里,zsh通常进行模式匹配,即def*将删除以def开头的第一个元素。 - Martin von Wittich
有关重新分配/删除数组切片的更多信息,请参见Zsh指南,第5.4.1节 -“参数替换:使用数组” - rampion
这个方法对我有效,用于删除zsh 5.9中插件列表中的一项 - Jérôme的答案导致错误,其中oh-my-zsh似乎将插件数组读取为单个字符串。 - flyingsandwich

19

自从版本4.2和5.0以来,zsh接受${name:|arrayname}语法。来自手册:

如果arrayname是数组变量的名称(注意,不是内容),则从name的替换中删除任何包含在arrayname中的元素。

所以,它正好做你期望的事情:

$ foo=(a b c)
$ excl=(b)
$ echo ${foo:|excl}
a c

7

foo = (1 2 3)

shift foo

print $foo会输出:2 3

这将删除第一个元素(您想要的是这个吗?)

[编辑]

要删除第i个元素,请使用以下代码:

foo[$i] = ()

即可。


不,我想删除它的条目,无论它在哪里(它不总是在开头)。 - Albert
$i是什么?我该如何获取它? - Albert
@ Dennis: 你的意思是 $i=b 吗?那是不行的。 foo(b)=() 是无效的。 - Albert
@Albert:不,我的意思是 i=2,这是这个答案中最后一个选项的意图。然而,这不是你要找的。 - Dennis Williamson

4
从数组中删除内容为“b”的元素:
foo=(a b c)
foo=(${foo#b})

这将把 (foo bar foobar) 转换为 (bar bar) - blueyed
不,它不会:foo=(foo bar foobar) ; foo=(${foo#bar}) ; echo $foo 返回 foo foobar - docwhat
1
错误的代码:foo=(a ab ac ad) ; foo=(${foo#a}) ; declare foo 输出 foo=(b c d)(期望输出 foo=(ab ac ad))。 - Franklin Yu
@TheDoctorWhat 他说的是 foo#foo 而不是 foo#bar - Dessa Simpson
澄清一下,foo=(foo bar foobar barfoo); foo=(${foo#bar}); declare foo 返回 foo=( foo foobar foo ) - Dessa Simpson

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