在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个回答

30

如果你需要从一个包含对象或结构化数据的数组中删除多个值,array_filter() 是最好的选择。回调函数返回 true 的条目将被保留。

$array = [
    ['x'=>1,'y'=>2,'z'=>3], 
    ['x'=>2,'y'=>4,'z'=>6], 
    ['x'=>3,'y'=>6,'z'=>9]
];

$results = array_filter($array, function($value) {
    return $value['x'] > 2; 
}); //=> [['x'=>3,'y'=>6,z=>'9']]

26
如果你需要从一个关联数组中移除多个元素,你可以使用array_diff_key()(结合array_flip()函数使用):
$my_array = array(
  "key1" => "value 1",
  "key2" => "value 2",
  "key3" => "value 3",
  "key4" => "value 4",
  "key5" => "value 5",
);

$to_remove = array("key2", "key4");

$result = array_diff_key($my_array, array_flip($to_remove));

print_r($result);

输出:

Array ( [key1] => value 1 [key3] => value 3 [key5] => value 5 ) 

为什么这个被低估了呢? - Fr0zenFyr
1
由于研究人员很难消化那些充斥着冗余信息的页面,这个经典页面的“研究体验”非常受损。 - mickmackusa

23

关联数组

对于关联数组,请使用unset

$arr = array('a' => 1, 'b' => 2, 'c' => 3);
unset($arr['b']);

// RESULT: array('a' => 1, 'c' => 3)

数字数组

对于数字数组,请使用array_splice函数:

$arr = array(1, 2, 3);
array_splice($arr, 1, 1);

// RESULT: array(0 => 1, 1 => 3)

注意

unset在处理数字数组时不会产生错误,但会破坏索引:

$arr = array(1, 2, 3);
unset($arr[1]);

// RESULT: array(0 => 1, 2 => 3)

22

unset()函数将指定的变量销毁。

unset()函数在函数内部的行为取决于你试图销毁的变量类型。

如果在函数内部销毁了一个全局变量,那么只会销毁局部变量。调用环境中的变量将保留与调用unset()之前相同的值。

<?php
    function destroy_foo()
    {
        global $foo;
        unset($foo);
    }

    $foo = 'bar';
    destroy_foo();
    echo $foo;
?>

以上代码的答案将是bar

在函数内部unset()一个全局变量:

<?php
    function foo()
    {
        unset($GLOBALS['bar']);
    }

    $bar = "something";
    foo();
?>

20
// Remove by value
function removeFromArr($arr, $val)
{
    unset($arr[array_search($val, $arr)]);
    return array_values($arr);
}

这个仅包含代码的答案不稳定。如果array_search()没有找到目标值,则其返回值为false将有效地删除不需要且对输入数据有害的[0]键元素。我敦促研究人员不要使用这段代码片段。 - mickmackusa

16

解决方案:

  1. 要删除一个元素,请使用unset()
unset($array[3]);
unset($array['foo']);
  • 如果需要删除多个不连续的元素,使用unset()
  • unset($array[3], $array[5]);
    unset($array['foo'], $array['bar']);
    
    1. 要删除多个连续的元素,请使用array_splice()
    array_splice($array, $offset, $length);
    

    进一步解释:

    使用这些函数可以从PHP中删除对这些元素的所有引用。如果您想保留数组中的一个键,但其值为空,请将空字符串分配给该元素:

    $array[3] = $array['foo'] = '';
    

    除了语法之外,使用 unset() 和将元素赋值为''之间存在着逻辑上的区别。前者表示“这个元素不再存在”,而后者表示“这个元素仍然存在,但其值为空字符串。”

    如果您正在处理数字,将其赋值为0可能是一个更好的选择。因此,如果一家公司停止生产XL1000型号的齿轮,它会更新其库存:

    unset($products['XL1000']);
    

    然而,如果暂时缺少XL1000链轮,但计划本周晚些时候从工厂收到新的货运批次,那就更好了:

    $products['XL1000'] = 0;
    

    如果您使用unset()函数删除数组的某个元素,PHP 会自动调整数组的内部结构以保证数组中的循环仍然能够正确工作。但是,PHP 不会将数组压缩以填充删除元素后产生的空洞。这就是我们说所有的数组都是关联数组的原因,即使它们看起来是数字索引数组。下面是一个例子:
    // Create a "numeric" array
    $animals = array('ant', 'bee', 'cat', 'dog', 'elk', 'fox');
    print $animals[1];  // Prints 'bee'
    print $animals[2];  // Prints 'cat'
    count($animals);    // Returns 6
    
    // unset()
    unset($animals[1]); // Removes element $animals[1] = 'bee'
    print $animals[1];  // Prints '' and throws an E_NOTICE error
    print $animals[2];  // Still prints 'cat'
    count($animals);    // Returns 5, even though $array[5] is 'fox'
    
    // Add a new element
    $animals[ ] = 'gnu'; // Add a new element (not Unix)
    print $animals[1];  // Prints '', still empty
    print $animals[6];  // Prints 'gnu', this is where 'gnu' ended up
    count($animals);    // Returns 6
    
    // Assign ''
    $animals[2] = '';   // Zero out value
    print $animals[2];  // Prints ''
    count($animals);    // Returns 6, count does not decrease
    

    要将数组压缩为一个密集填充的数值数组,请使用array_values()

    $animals = array_values($animals);
    

    或者,array_splice() 会自动重新索引数组以避免留下空洞:

    // Create a "numeric" array
    $animals = array('ant', 'bee', 'cat', 'dog', 'elk', 'fox');
    array_splice($animals, 2, 2);
    print_r($animals);
    Array
    (
        [0] => ant
        [1] => bee
        [2] => elk
        [3] => fox
    )
    

    如果您将数组用作队列并希望在仍允许随机访问的情况下从队列中删除项,则此功能很有用。要安全地从数组中删除第一个或最后一个元素,请分别使用array_shift()array_pop()


    14

    遵循默认函数:

    • PHP: unset

    unset()会摧毁指定的变量。有关更多信息,请参见PHP unset

    $Array = array("test1", "test2", "test3", "test3");
    
    unset($Array[2]);
    
    • PHP: array_pop

    array_pop()函数删除数组的最后一个元素。要获取更多信息,您可以参考PHP array_pop

    $Array = array("test1", "test2", "test3", "test3");
    
    array_pop($Array);
    
    • PHP: array_splice

    array_splice() 函数从数组中移除选定的元素,并用新元素替换它。更多信息,请参见PHP array_splice

    $Array = array("test1", "test2", "test3", "test3");
    
    array_splice($Array,1,2);
    
    • PHP: array_shift

    array_shift() 函数从数组中移除第一个元素。更多信息,请参见 PHP array_shift

    $Array = array("test1", "test2", "test3", "test3");
    
    array_shift($Array);
    

    11

    我只是想说我有一个特定的对象,它具有可变属性(基本上它映射了一张表格,我正在改变表格中的列,因此,反映表格的对象属性也会变化):

    class obj {
        protected $fields = array('field1','field2');
        protected $field1 = array();
        protected $field2 = array();
        protected loadfields(){}
        // This will load the $field1 and $field2 with rows of data for the column they describe
        protected function clearFields($num){
            foreach($fields as $field) {
                unset($this->$field[$num]);
                // This did not work the line below worked
                unset($this->{$field}[$num]); // You have to resolve $field first using {}
            }
        }
    }
    

    $fields 的整个目的只是为了让我在更改属性时不必到代码的各个地方查找,只需查看类的开头并更改属性列表和 $fields 数组内容以反映新属性即可。


    10

    有两种方法可以删除数组的第一个元素,同时保持索引顺序,而且如果您不知道第一个元素的键名。

    解决方案#1

    // 1 is the index of the first object to get
    // NULL to get everything until the end
    // true to preserve keys
    $array = array_slice($array, 1, null, true);
    

    解决方案 #2

    // Rewinds the array's internal pointer to the first element
    // and returns the value of the first array element.
    $value = reset($array);
    // Returns the index element of the current array position
    $key = key($array);
    unset($array[$key]);
    

    对于这个示例数据:

    $array = array(10 => "a", 20 => "b", 30 => "c");
    

    您必须得到这个结果:

    array(2) {
      [20]=>
      string(1) "b"
      [30]=>
      string(1) "c"
    }
    

    3
    在你回答之前,已经有多次演示了array_slice()unset()方法。这个回答是冗余的,并且只会损害研究者的体验。 - mickmackusa
    1
    @mickmackusa 但我的回答干净明了。 - Nabi K.A.Z.
    1
    ......而且是多余的。您没有为此页面添加任何特定于元素删除的独特价值。您已经偏离了主题,谈论如何定位第一个元素的键。OP没有提到想要定位第一个元素。您可能被其他答案在这个非常拥挤的页面中阅读而误入不同的范围。为了改善研究人员的体验,可以安全地删除此答案。 - mickmackusa

    9

    编辑

    如果您不能确定该对象在该数组中,您需要添加检查:

    if(in_array($object,$array)) unset($array[array_search($object,$array)]);
    

    原始答案

    如果你想通过对象的引用来删除数组中的特定对象,可以执行以下操作:

    unset($array[array_search($object,$array)]);
    

    例子:

    <?php
    class Foo
    {
        public $id;
        public $name;
    }
    
    $foo1 = new Foo();
    $foo1->id = 1;
    $foo1->name = 'Name1';
    
    $foo2 = new Foo();
    $foo2->id = 2;
    $foo2->name = 'Name2';
    
    $foo3 = new Foo();
    $foo3->id = 3;
    $foo3->name = 'Name3';
    
    
    $array = array($foo1,$foo2,$foo3);
    unset($array[array_search($foo2,$array)]);
    
    echo '<pre>';
    var_dump($array);
    echo '</pre>';
    ?>
    

    结果:

    array(2) {
    [0]=>
        object(Foo)#1 (2) {
            ["id"]=>
            int(1)
            ["name"]=>
            string(5) "Name1"
        }
    [2]=>
        object(Foo)#3 (2) {
            ["id"]=>
            int(3)
            ["name"]=>
            string(5) "Name3"
        }
    }
    

    请注意,如果对象出现多次,则只会删除第一次出现!

    这个答案不稳定。如果array_search()没有找到目标数组键,则其返回值将有效地破坏[0]键入的元素。这段代码很危险,应该被移除。之前有一些回答没有犯这个错误。 - mickmackusa
    @mickmackusa,感谢你的提示,已经添加了一项检查。 - Sam Tigle
    使用in_array()进行可能的完整数组扫描,然后再使用array_search()进行另一个可能的完整扫描,这绝对不是我建议任何人做的事情。这只是一种不好的实践。我的立场仍然是--这个答案犯了之前的答案没有犯的错误。纠正这个答案只会使它变得多余。如果删除这个答案,这个页面将会得到改善。 - mickmackusa

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