在PHP中删除数组中的一个元素

3051

有没有一种简单的方法可以使用PHP从数组中删除元素,使得foreach($array)不再包括该元素?

我曾认为将其设置为null会起作用,但显然这并不起作用。


17
我希望你能翻译以下内容:Konrad的回答是针对所述问题最简单的。使用unset()后,数组的迭代将不再包括已移除的值。另一方面,Stevan的回答很充分,实际上,这就是我正在寻找的答案 - 但不是该帖子的原始问题 :) Konrad的回答是最简单的解决所提出问题的方法。使用unset()函数之后,数组的迭代将不再包括已删除的值。然而,Stevan的回答更加详尽,并且事实上,那正是我一开始寻找的答案 - 但并非该帖作者想要的答案 :) - brandizzi
48
在手册中容易找到并不意味着问题不能在StackOverflow上提问。如果问题是StackOverflow的重复问题,则可能不适合在这里提问。StackOverflow是一个很好的去处,甚至在查看手册之前就可以寻找答案。 - Dan Nissenbaum
7
@unset($array[$key]); $array = array_values($array);翻译:移除数组中键为$key的元素;将数组重新索引,使其键从0开始。 - trojan
2
如果您想从数组的数组(关联数组)中删除键,请参见以下解决方案:https://dev59.com/DHI-5IYBdhLWcg3wQV4Z#47978980 - Somnath Muluk
3
将数组键值设置为null意味着包含具有null值的键。该键仍然存在。 - blakroku
显示剩余2条评论
26个回答

3575
有不同的方法可以删除数组元素,其中一些对于特定任务比其他方法更有用。
删除单个数组元素的方法有两种,可以使用unset(),也可以使用array_splice()
按键还是按值删除?
如果您知道要删除的元素的值,但不知道键,可以使用array_search()来获取键。 这仅在元素不重复出现时有效,因为array_search()只返回第一个匹配项。 unset()表达式
注意:当你使用unset()函数时,数组的键不会改变。 如果你想重新索引键,你可以在unset()函数之后使用array_values()函数, 它将把所有键转换为从0开始的数字枚举键(数组仍然是一个列表)。
示例代码:
$array = [0 => "a", 1 => "b", 2 => "c"];
unset($array[1]);
          // ↑ Key of element to delete

示例输出:

[
    [0] => a
    [2] => c
]

array_splice() 函数

如果你使用 array_splice(),整数键会自动重新索引, 但是关联键(字符串键)不会改变 — 与 unset() 后的 array_values() 不同, 后者会将所有键转换为数字键。

注意: array_splice() 需要偏移量(offset),而不是键(key),作为第二个参数;偏移量 = array_flip(array_keys(array))[key]

示例代码:

$array = [0 => "a", 1 => "b", 2 => "c"];
array_splice($array, 1, 1);
                  // ↑ Offset of element to delete

示例输出:

[
    [0] => a
    [1] => c
]

array_splice(),和unset()一样,通过引用来操作数组。你不需要将返回值重新赋给数组。

删除多个数组元素

如果你想删除多个数组元素,并且不想多次调用unset()array_splice(),你可以使用array_diff()array_diff_key()函数,具体取决于你是知道要从数组中删除的值还是键。

array_diff()函数

如果你知道要删除的数组元素的值,那么你可以使用array_diff()。和unset()一样,它不会改变数组的键。

示例代码:

$array = [0 => "a", 1 => "b", 2 => "c", 3 => "c"];
$array = array_diff($array, ["a", "c"]);
                         // └────────┘
                         // Array values to delete

示例输出:

[
    [1] => b
]

array_diff_key() 函数

如果你知道你想要删除的元素的键,那么你可以使用 array_diff_key() 函数。 你必须确保将键作为第二个参数中的键传递,而不是作为值。 键不会重新索引。

示例代码:

$array = [0 => "a", 1 => "b", 2 => "c"];
$array = array_diff_key($array, [0 => "xy", "2" => "xy"]);
                              // ↑           ↑
                              // Array keys of elements to delete

示例输出:

[
    [1] => b
]

如果你想使用unset()array_splice()来删除具有相同值的多个元素,你可以使用array_keys()来获取特定值的所有键,然后删除所有元素。

array_filter()函数

如果你想删除数组中所有具有特定值的元素,可以使用array_filter()
示例代码:
$array = [0 => "a", 1 => "b", 2 => "c"];
$array = array_filter($array, static function ($element) {
    return $element !== "b";
    //                   ↑
    // Array value which you want to delete
});

示例输出:

[
    [0] => a
    [2] => c
]

31
@AlexandruRada,不,你说的“不要使用这个”是无意义的。当你将数组视为字典时,你可以安全地使用这种方法。只有当你期望连续的数字索引时,你才需要使用其他方法。 - Konrad Rudolph
9
unset 可以有多个参数:void unset ( mixed $var [, mixed $... ] ) - Константин Ван
4
array_filter也是一个可行的方法。如果您不想改变数组,这尤其好用,但它也不会重新索引,这可能是json_encode存在问题的地方。http://php.net/manual/en/function.json-encode.php#94157 - dotnetCarpenter
2
unset is not a function but a language construct (and a keyword). It must not and cannot be prefixed with \ - hvertous
4
为什么要使用反斜杠?这只会让不了解其含义的人感到困惑,而对于那些了解的人来说,他们会知道是否需要使用它们。在我看来,这完全是不必要的。 - Clonkex
显示剩余11条评论

1423
应该注意,unset()函数不会影响到数组的索引值,这在使用字符串作为索引(将数组视为哈希表)时是预期的行为,但在处理整数索引数组时可能会让人感到惊讶。
$array = array(0, 1, 2, 3);
unset($array[2]);
var_dump($array);
/* array(3) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [3]=>
  int(3)
} */

$array = array(0, 1, 2, 3);
array_splice($array, 2, 1);
var_dump($array);
/* array(3) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(3)
} */

如果您想规范化整数键,可以使用array_splice()。另一种选择是在使用unset()之后使用array_values()

$array = array(0, 1, 2, 3);

unset($array[2]);
$array = array_values($array);
var_dump($array);
/* array(3) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(3)
} */

51
值得注意的是,当你使用array_splice()函数时,你需要知道要删除的元素的偏移量(offset),而不是键值(key)! - Tom
20
对于一个普通的数组(连续整数索引),其偏移量即为其索引。这就是 array_splice 等函数有意义的地方之一。 - Stefan Gehrig
5
好的,如果您在使用splice之前修改了数组,请记住这一点。 - Tom
4
仅仅进行了一个从巨大数组中删除大量元素的基本测试后,array_splice似乎更快且占用的内存更少。这与我的预期相符:array_values()似乎在对数组进行复制,而array_splice则直接在原数组上操作。 - Doug Kavendek
4
array_values是一个有用的方法,当你在循环中删除元素并希望索引保持一致,但在循环后想要将它们压缩时可以使用。 - Rorrik
显示剩余4条评论

426
  // Our initial array
  $arr = array("blue", "green", "red", "yellow", "green", "orange", "yellow", "indigo", "red");
  print_r($arr);

  // Remove the elements who's values are yellow or red
  $arr = array_diff($arr, array("yellow", "red"));
  print_r($arr);

这是上面代码的输出结果:

Array
(
    [0] => blue
    [1] => green
    [2] => red
    [3] => yellow
    [4] => green
    [5] => orange
    [6] => yellow
    [7] => indigo
    [8] => red
)

Array
(
    [0] => blue
    [1] => green
    [4] => green
    [5] => orange
    [7] => indigo
)

现在,array_values()函数可以很好地重新索引数字数组,但它将删除所有的键名字符串,并用数字替换它们。如果您需要保留键名(字符串),或者如果所有键都是数字,则重新索引数组,请使用array_merge()函数:

$arr = array_merge(array_diff($arr, array("yellow", "red")));
print_r($arr);

输出

Array
(
    [0] => blue
    [1] => green
    [2] => green
    [3] => orange
    [4] => indigo
)

$get_merged_values = array_merge($data['res'],$data['check_res']); 当我打印这个 print_r($get_merged_values); 它会显示以下内容。Array ( [0] => Array ( [menu_code] => 2 [menu_name] => Plant [menu_order_no] => 1 ) [1] => Array ( [menu_code] => 3 [menu_name] => Line [menu_order_no] => 2 ) ) 但是我需要使用 $get_merged_values['menu_code'] 和 $get_merged_values['menu_name'] 来获取 menu_code 和 menu_name 的值,而不是使用 $get_merged_values[0][menu_code] 和 $get_merged_values[0][menu_name]。 请告诉我如何做到这一点? - heart hacker
问题的措辞有误导性。如果在foreach循环中要删除$arr[$i],并且有多个元素具有相同的值,则此方法将无效。 - Jed Lynch
1
array_merge(array_diff( you saved my time, thanks for both the examples, 1.keys are not re-indexed and another one with keys are indexed again from 0...n - Mohammed Sufian

242
$key = array_search($needle, $array);
if ($key !== false) {
    unset($array[$key]);
}

9
需要澄清的是,此答案是针对已知值但不知道键名时删除元素的操作。需要注意的是,它只会删除该值的第一个实例;若要查找该值的所有键名,请使用 array_keys 函数。 - ToolmakerSteve
如果有多个元素具有相同的值,这将无法工作。 - Jed Lynch

109
unset($array[$index]);

77

此外,对于一个有名称的元素:

unset($array["elementName"]);

$a = array("A"=>1, "B"=>2, "C"=>"a"); print_r($a); unset($a["B"]); print_r($a);输出结果为:Array ( [A] => 1 [B] => 2 [C] => a ), Array ( [A] => 1 [C] => a ) - DefenestrationDay
似乎您无法取消由字符串索引的数组元素(会生成“致命错误:无法取消字符串偏移量”)。我认为这并不总是这种情况,但肯定在PHP 5.3.10及更早版本中。 - carpii
7
PHP能够从关联数组中删除元素。当你试图在字符串上使用unset($var['key'])时,会导致致命错误的发生,因为这个函数只能用于数组。例如:$array = array( 'test' => 'value', 'another' => 'value', ); unset($array['test']); // 正如预期一样,删除了数组中的"test"元素$array = 'test'; unset($array['test']); // 正如预期一样,抛出了"Fatal error: Cannot unset string offsets"错误信息 - Jimbo
在这里,您必须知道关键名称,最好是:https://dev59.com/pnRC5IYBdhLWcg3wOeWB#52826684 - Nabi K.A.Z.
@Eran已经在2008年推荐了unset()!如果你想改进那个建议,你应该编辑那个答案。这个多标签页上有太多冗余内容了! - mickmackusa

75

如果你有一个数值索引数组,其中所有的值都是唯一的(或者它们不是唯一的,但你希望删除特定值的所有实例),你可以简单地使用array_diff()函数来移除匹配元素,就像这样:

$my_array = array_diff($my_array, array('Value_to_remove'));
例如:
$my_array = array('Andy', 'Bertha', 'Charles', 'Diana');
echo sizeof($my_array) . "\n";
$my_array = array_diff($my_array, array('Charles'));
echo sizeof($my_array);

这会显示以下内容:

4
3
在这个例子中,具有值'Charles'的元素被删除,这可以通过sizeof()调用进行验证,初始数组的大小为4, 删除后的大小为3。

如果两个元素具有相同的值,这将无法工作。 - Jed Lynch

40

删除数组中的单个元素

unset()

$array1 = array('A', 'B', 'C', 'D', 'E');
unset($array1[2]); // Delete known index(2) value from array
var_dump($array1);

输出结果将是:

array(4) {
  [0]=>
  string(1) "A"
  [1]=>
  string(1) "B"
  [3]=>
  string(1) "D"
  [4]=>
  string(1) "E"
}

如果您需要重新索引数组:

$array1 = array_values($array1);
var_dump($array1);

那么输出结果将会是:

array(4) {
  [0]=>
  string(1) "A"
  [1]=>
  string(1) "B"
  [2]=>
  string(1) "D"
  [3]=>
  string(1) "E"
}

从数组末尾弹出元素 - 返回被移除元素的值

mixed array_pop(array &$array)

$stack = array("orange", "banana", "apple", "raspberry");
$last_fruit = array_pop($stack);
print_r($stack);
print_r('Last Fruit:'.$last_fruit); // Last element of the array
输出将会是
Array
(
    [0] => orange
    [1] => banana
    [2] => apple
)
Last Fruit: raspberry

从数组中删除第一个元素(红色)并返回被删除元素的值

mixed array_shift ( array &$array )

$color = array("a" => "red", "b" => "green" , "c" => "blue");
$first_color = array_shift($color);
print_r ($color);
print_r ('First Color: '.$first_color);

输出结果将为:

Array
(
    [b] => green
    [c] => blue
)
First Color: red

1
array_shift 会重新索引键名,如果它是整数,则不好,因此您可以使用此方法:https://dev59.com/pnRC5IYBdhLWcg3wOeWB#52826684 - Nabi K.A.Z.
array_shift()的复杂度是O(n)(由于重新索引数字索引),而array_pop()的复杂度是O(1)。如何知道第一个元素的索引?只需开始一个foreach循环,并在第一次迭代中立即使用break命令。 - AmigoJack

39
<?php
    $stack = ["fruit1", "fruit2", "fruit3", "fruit4"];
    $fruit = array_shift($stack);
    print_r($stack);

    echo $fruit;
?>

输出:

[
    [0] => fruit2
    [1] => fruit3
    [2] => fruit4
]

fruit1

16
请注意,array_shift 只能删除数组中的第一个元素。同样地,使用 array_pop 来删除数组中的最后一个元素。 - Jasir
3
答案仅适用于数组的第一个元素,并不回答一般性问题。 - sweisgerber.dev
@sebweisgerber,你是对的,但我认为这个答案并没有错误,并且不需要对其进行投票。问题是删除一个元素,而没有提到任何位置。 - Saurabh Chandra Patel
1
这只涵盖了一个边缘情况。 - Jed Lynch
这种技术的实用性不高,正如先前所提到的。这个答案缺少了它的教育解释。 - mickmackusa

32
如果指定了索引:
$arr = ['a', 'b', 'c'];
$index = 0;    
unset($arr[$index]);  // $arr = ['b', 'c']

如果我们有值而不是索引:
$arr = ['a', 'b', 'c'];

// search the value to find index
// Notice! this will only find the first occurrence of value
$index = array_search('a', $arr);

if($index !== false){
   unset($arr[$index]);  // $arr = ['b', 'c']
}

因为如果找不到索引,unset()会自动删除数组的第一个元素!!!这不是我们想要的。所以if条件是必要的。

1
unset()在多年前的这个页面上已经被多次推荐过了。2011年就有人演示了使用array_search()unset()的方法。https://dev59.com/pnRC5IYBdhLWcg3wOeWB#8135667 这个答案没有为这个页面增加任何新价值。 - mickmackusa
@mickmackusa 也许你是对的,这个答案中的所有信息都可以在其他不同的答案中找到。但是,将它们全部放在一个答案中,针对不同的情况进行简单的解释,可能会为某些人节省时间。因此,我认为它可以被视为有价值的! - Ahmad Mobaraki
在很多情况下我同意你的看法。但是我认为编辑答案的目的是修正一些单词或小的技术错误,而不是扩展/改变它。无论如何,我自己花了一些时间浏览所有答案,并想出了一种简单有效的方法来解决问题,然后提出了这个解决方案,我觉得分享这个想法可能是一个好主意。我认为它获得一些赞的原因是其他人也有同样的情况,并且发现这个答案简单易懂且全面!@mickmackusa - Ahmad Mobaraki
只关注投票计数的问题在于它没有记录因为“读者疲劳”而放弃阅读其他答案的无数人。通过将冗余信息打包到更多的答案中,新的具有独特见解的答案很难被注意/阅读。请考虑一下那些实际上提供独特建议的新/新兴答案(已发布和未发布)。“如果未指定索引:”实际上应该说“如果指定了值:”--然后它应该说只删除第一个出现的值。 - mickmackusa
1
我觉得Ahmad的回复非常有帮助。 - oyvey
显示剩余3条评论

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