PHP数组按值删除(不是键)


885

我有一个如下的PHP数组:

$messages = [312, 401, 1599, 3, ...];

我想删除包含值的元素$del_val(例如$del_val=401),但是我不知道它的键。这可能会有所帮助:每个值只能存在一次

我正在寻找执行此任务的最简单功能。


1
@Adam Strudwick但是,如果在此数组上有很多删除,最好将它迭代一次并将其键值与值相同?
dzona 2013年


Answers:


1565

使用array_search()unset,尝试以下操作:

if (($key = array_search($del_val, $messages)) !== false) {
    unset($messages[$key]);
}

array_search()返回找到的元素的键,可使用将键从原始数组中删除该元素unset()。如果FALSE失败,它将返回,但是如果成功,它将返回false -y值(0例如,您的密钥),这就是为什么使用严格比较运算符的原因!==

if()语句将检查是否array_search()返回了值,并且只会执行一个操作。


14
$ messages = array_diff($ messages,array($ del_val))也会起作用吗?性能会更好吗?
亚当·斯特鲁德威克

9
@Adam为什么不测试呢?我的感觉是,array_diff()因为它会比较慢比较两个数组,而不是简单的通过搜索一个array_search()
Bojangles

22
即使这是有效的,您也应避免在这样的语句中分配值。只会惹麻烦。
adlawson 2011年

17
如果$key0什么呢?
evan,

16
如果您要搜索的值的键为0或其他任何假值,则不会取消设置该值,并且您的代码也将无法工作。你应该测试一下$key === false。(编辑-您知道了)
evan

671

好吧,从数组中删除一个元素基本上只是与一个元素设置不同

array_diff( [312, 401, 15, 401, 3], [401] ) // removing 401 returns [312, 15, 3]

概括性很好,如果需要,您可以同时删除任意多个元素。

免责声明:请注意,我的解决方案会生成一个数组的新副本,同时保持旧副本不变,这与接受的变异答案相反。选择您需要的那个。


32
这仅适用于可以转换为字符串的对象
nischayn22

7
我似乎说的是“解析错误” [$element],而是使用了array($element)。没什么大不了的,只是想让任何有类似问题的人知道他们并不孤单
Angad

8
当然,我假设PHP 5.4现在已成为大多数,以废除旧的表示法。谢谢你的发言。
Rok Kralj 2013年

22
值得注意的是,出于某种原因array_diff(string) $elem1 === (string) $elem2其用作相等条件,而不是$elem1 === $elem2您期望的那样。@ nischayn22指出的问题是由此导致的。如果您希望将某些东西用作可用于任意元素数组(可能是对象)的实用函数,则出于这个原因,Bojangle的答案可能会更好。
Mark Amery 2014年

4
还要注意,此方法在内部对每个参数执行排序array_diff(),因此将运行时从O(n)推到O(n lg n)。
杰克·

115

一种有趣的方法是使用array_keys()

foreach (array_keys($messages, 401, true) as $key) {
    unset($messages[$key]);
}

array_keys()函数使用两个附加参数来仅返回特定值的键以及是否需要严格检查(即,使用===进行比较)。

这也可以删除具有相同值的多个数组项(例如[1, 2, 3, 3, 4])。


3
@blasteralfredΨ线性搜索为O(n); 我不确定为什么您似乎认为这是一个问题。
杰克

1
是的,这对于选择多个数组项/键有效。
Oki Erie Rinaldi 2014年

3
这对于可能不包含所有唯一值的数组是最好的。
Derokorian

问题在于,它使键的索引处于排序状态:[0]-a,[2]-b([1]消失了,但是数组仍然错过了它)
Rodniko 2014年

3
@Rodniko在这种情况下,您同样需要array_values();其余键仍然在同一顺序的,所以从技术上讲不是“无序”
杰克

55

如果您确定您的数组将仅包含一个具有该值的元素,则可以

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

但是,如果您的值可能在数组中出现多次,则可以这样做

$array = array_filter($array, function($e) use ($del_val) {
    return ($e !== $del_val);
});

注意:第二个选项仅适用于带有闭包的 PHP5.3 +


41
$fields = array_flip($fields);
unset($fields['myvalue']);
$fields = array_flip($fields);

11
仅当您的数组不包含您要删除的重复值时,此方法才起作用。
jberculo 2014年

2
@jberculo有时候,你需要什么,在某些情况下,它节省了我做一个阵列上它独特的aswel
DarkMukke

也许可以,但是我会使用专门设计的功能来做到这一点,而不仅仅是仅仅是基本上用于其他用途的功能的幸运副作用。这也会使您的代码不那么透明。
jberculo

消息指出“每个值只能存在一次”,这应该起作用。如果海报使用了smae变量名并添加了一点说明
那就

2
显然,与所选解决方案相比,这是最快的,我做了小型基准测试。
AMB

28

看一下下面的代码:

$arr = array('nice_item', 'remove_me', 'another_liked_item', 'remove_me_also');

你可以做:

$arr = array_diff($arr, array('remove_me', 'remove_me_also'));

这将为您提供以下数组:

array('nice_item', 'another_liked_item')

1
对于关联数组,您必须使用array_diff_assoc()
TheCodeMachine 2015年

5
这和这个答案有什么不同?
random_user_name 2016年

26

最好的方法是 array_splice

array_splice($array, array_search(58, $array ), 1);

最佳理由位于http://www.programmerinterview.com/index.php/php-questions/how-to-delete-an-element-from-an-array-in-php/


4
这不适用于关联数组和键中有空格的数组,例如[1, 2, 4 => 3]
杰克·

抱歉,这将起作用。请阅读我提供的文章链接
-Airy

4
不会的 考虑一下我上面的评论;在我使用您的代码删除值后3,数组将是[1, 2, 3]; 换句话说,该值未删除。明确地说,我并不是说它在所有情况下都会失败,仅此一种。
杰克

1
array_splice是最好的方法,删除后未设置将不会调整数组索引
Raaghu 2015年

21

或者简单地,手动方式:

foreach ($array as $key => $value){
    if ($value == $target_value) {
        unset($array[$key]);
    }
}

这是最安全的方法,因为您可以完全控制阵列


1
使用array_splice()代替unset()也会重新排列数组索引,在这种情况下可能会更好。
Daniele Orlando


20

如果您有PHP 5.3+,则只有一行代码:

$array = array_filter($array, function ($i) use ($value) { return $i !== $value; }); 

你确定吗?那封没有获得$value,所以实际上它已被放入一个微型类使您可以访问$value封闭内....
random_user_name

@cale_b,我已经更新了示例。另外这里的参考:php.net/manual/en/functions.anonymous.php
David Lin

3
如果您将整个代码库称为“一行代码”,则最好将其写在一行上
Milan Simek

16
function array_remove_by_value($array, $value)
{
    return array_values(array_diff($array, array($value)));
}

$array = array(312, 401, 1599, 3);

$newarray = array_remove_by_value($array, 401);

print_r($newarray);

输出量

Array ( [0] => 312 [1] => 1599 [2] => 3 )


2
我不确定这是否更快,因为此解决方案涉及多个函数调用。
朱利安·保罗·戴亚格

13

你可以做:

unset($messages[array_flip($messages)['401']]);

说明401翻转数组后,删除具有键的元素。


如果要保留状态,则必须非常小心。因为所有将来的代码都必须具有值而不是键。
saadlulu 2015年

1
@saadlulu $ messages数组将不会被翻转,因为array_flip()不会影响原始数组,因此应用前一行后得到的数组将是相同的,除了不需要的结果将被删除。
古拉什

2
不知道这是否正确,如果有多个元素的值为401
Zippp

这仍将保留密钥。
SzabolcsPáll


6

借用了underscore.JS _.reject的逻辑,并创建了两个函数(人们更喜欢函数!)

array_reject_value:该函数只是拒绝指定的值(也适用于PHP4、5、7)

function array_reject_value(array &$arrayToFilter, $deleteValue) {
    $filteredArray = array();

    foreach ($arrayToFilter as $key => $value) {
        if ($value !== $deleteValue) {
            $filteredArray[] = $value;
        }
    }

    return $filteredArray;
}

array_reject:该函数只是拒绝可调用方法(适用于PHP> = 5.3)

function array_reject(array &$arrayToFilter, callable $rejectCallback) {

    $filteredArray = array();

    foreach ($arrayToFilter as $key => $value) {
        if (!$rejectCallback($value, $key)) {
            $filteredArray[] = $value;
        }
    }

    return $filteredArray;
}

因此,在当前示例中,我们可以按以下方式使用上述功能:

$messages = [312, 401, 1599, 3, 6];
$messages = array_reject_value($messages, 401);

甚至更好:(因为这给了我们更好的语法,就像array_filter一样)

$messages = [312, 401, 1599, 3, 6];
$messages = array_reject($messages, function ($value) {
    return $value === 401;
});

上面的代码可以用于更复杂的东西,比如说我们想删除所有大于或等于401的值,我们可以简单地做到这一点:

$messages = [312, 401, 1599, 3, 6];
$greaterOrEqualThan = 401;
$messages = array_reject($messages, function ($value) use $greaterOrEqualThan {
    return $value >= $greaterOrEqualThan;
});


确实是的。正如我在帖子中已经说过的:“或者甚至更好:(因为这给了我们更好的语法,就像使用array_filter一样)”。有时,您实际上只需要将函数拒绝作为下划线,并且它实际上与过滤器相反(并且您需要使用尽可能少的代码来获得它)。这就是功能的作用。这是拒绝值的简单方法。
John Skoumbourdis

6
$array = array("apple", "banana",'mango');
$array = array_filter($array, function($v) { return $v != "apple"; });

试试这个,这是按值删除元素的最佳,最快方法


5

@Bojangles的回答确实帮助了我。谢谢。

就我而言,数组可以是关联的,也可以不是关联的,所以我添加了以下函数

function test($value, $tab) {

 if(($key = array_search($value, $tab)) !== false) {
    unset($tab[$key]); return true;

 } else if (array_key_exists($value, $tab)){
        unset($tab[$value]); return true;

 } else {
    return false; // the $value is not in the array $tab
 }

}

问候



4

接受的答案会将数组转换为关联数组,因此,如果您希望将其与接受的答案保持为非关联数组,则可能也必须使用array_values

if(($key = array_search($del_val, $messages)) !== false) {
    unset($messages[$key]);
    $arr = array_values($messages);
}

参考在这里




4

我知道这根本不是高效的,而是简单,直观且易于阅读。
因此,如果有人正在寻找一种不太理想的解决方案,可以将其扩展为使用更多值或更特定的条件,那么这是一个简单的代码:

$result = array();
$del_value = 401;
//$del_values = array(... all the values you don`t wont);

foreach($arr as $key =>$value){
    if ($value !== $del_value){
        $result[$key] = $value;
    }

    //if(!in_array($value, $del_values)){
    //    $result[$key] = $value;
    //}

    //if($this->validete($value)){
    //      $result[$key] = $value;
    //}
}

return $result


3

如果您不知道它的密钥,那就意味着它无关紧要。

您可以将值作为键,这意味着它将立即找到值。胜过一次又一次地搜索所有元素。

$messages=array();   
$messages[312] = 312;    
$messages[401] = 401;   
$messages[1599] = 1599;   
$messages[3] = 3;    

unset($messages[3]); // no search needed

仅适用于可以转换为字符串的对象。
Emile Bergeron

2

使用or操作员的单线:

($key = array_search($del_val, $messages)) !== false or unset($messages[$key]);

2

您可以参考以下网址:以获取功能

array-diff-key()

<?php
$array1 = array('blue'  => 1, 'red'  => 2, 'green'  => 3, 'purple' => 4);
$array2 = array('green' => 5, 'blue' => 6, 'yellow' => 7, 'cyan'   => 8);

var_dump(array_diff_key($array1, $array2));
?>

然后输出应该是

array(2) {
  ["red"]=>
  int(2)
  ["purple"]=>
  int(4)
}


1

我认为最简单的方法是使用带有foreach循环的函数:

//This functions deletes the elements of an array $original that are equivalent to the value $del_val
//The function works by reference, which means that the actual array used as parameter will be modified.

function delete_value(&$original, $del_val)
{
    //make a copy of the original, to avoid problems of modifying an array that is being currently iterated through
    $copy = $original;
    foreach ($original as $key => $value)
    {
        //for each value evaluate if it is equivalent to the one to be deleted, and if it is capture its key name.
        if($del_val === $value) $del_key[] = $key;
    };
    //If there was a value found, delete all its instances
    if($del_key !== null)
    {
        foreach ($del_key as $dk_i)
        {
            unset($original[$dk_i]);
        };
        //optional reordering of the keys. WARNING: only use it with arrays with numeric indexes!
        /*
        $copy = $original;
        $original = array();
        foreach ($copy as $value) {
            $original[] = $value;
        };
        */
        //the value was found and deleted
        return true;
    };
    //The value was not found, nothing was deleted
    return false;
};

$original = array(0,1,2,3,4,5,6,7,4);
$del_val = 4;
var_dump($original);
delete_value($original, $del_val);
var_dump($original);

输出将是:

array(9) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(2)
  [3]=>
  int(3)
  [4]=>
  int(4)
  [5]=>
  int(5)
  [6]=>
  int(6)
  [7]=>
  int(7)
  [8]=>
  int(4)
}
array(7) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(2)
  [3]=>
  int(3)
  [5]=>
  int(5)
  [6]=>
  int(6)
  [7]=>
  int(7)
}

1

在使用箭头功能的PHP 7.4中:

$messages = array_filter($messages, fn ($m) => $m != $del_val);

要使其保持非关联数组,请使用array_values()以下代码进行包装:

$messages = array_values(array_filter($messages, fn ($m) => $m != $del_val));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.