ChatGPT解决这个技术问题 Extra ChatGPT

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

我有一个 PHP 数组,如下所示:

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

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

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

@Adam Strudwick但是如果您在这个数组上有很多删除,最好迭代一次并使其键与值相同?

O
Orwellophile

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

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

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

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


$messages = array_diff($messages, array($del_val)) 也可以吗?在性能上会更好吗?
@Adam 为什么不测试一下?我的感觉是array_diff() 会比较慢,因为它是比较两个 数组,而不是像array_search() 那样简单地搜索一个
即使这是有效的,你也应该避免在这样的语句中赋值。它只会让你陷入困境。
如果您要搜索的值具有 0 键或任何其他虚假值,则不会取消设置该值,并且您的代码将不起作用。您应该测试 $key === false。 (编辑-你明白了)
请注意,这不会重置数组键。
R
Rok Kralj

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

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

它很好地概括了,如果你愿意,你可以同时删除尽可能多的元素。

免责声明:请注意,我的解决方案会生成数组的新副本,同时保持旧副本完整,而接受的答案会发生变异。选择你需要的那个。


这仅适用于可以转换为字符串的对象
我似乎在说 [$element] 时遇到了“解析错误”,我改用了 array($element)。没什么大不了的,只是想让有类似问题的人知道他们并不孤单
当然,我假设 PHP 5.4 现在大部分是放弃旧的符号。谢谢你的评论。
值得注意的是,出于某种原因,array_diff 使用 (string) $elem1 === (string) $elem2 作为其相等条件,而不是您可能期望的 $elem1 === $elem2。 @nischayn22 指出的问题是由此产生的结果。如果您希望将某些东西用作适用于任意元素数组(可能是对象)的实用函数,出于这个原因,Bojangle 的答案可能会更好。
另请注意,此方法在内部对 array_diff() 的每个参数执行排序,因此将运行时从 O(n) 微调到 O(n lg n)。
d
d-_-b

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

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

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

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


是的,这对于选择多个数组项/键是有效的。
这对于可能不包含所有唯一值的数组是最好的。
问题是它使键的索引保持不变: [0] - a, [2] - b ([1] 消失了,但数组仍然错过了它)
@Rodniko 在这种情况下您也需要 array_values() ;其余的键仍然是相同的顺序,所以从技术上讲它不是“未排序的”
很好的答案 - 我不知道 array_keys() 可以进行搜索。
d
d-_-b

如果您确定您的数组将只包含一个具有该值的元素,您可以这样做

$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);
});

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


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

这仅在您的数组不包含您尝试删除的值以外的重复值时才有效。
@jberculo,有时这正是您所需要的,在某些情况下,它可以节省我在它上面做一个独特的数组
也许吧,但我会使用专门设计的函数,而不是仅仅作为一个基本上用于其他用途的函数的幸运副作用。它还会使您的代码不那么透明。
该消息指出“每个值只能存在一次”这应该有效。如果张贴者使用了 smae 变量名并添加了一些解释,那就太好了
显然,与选定的解决方案相比,这是最快的,我做了小的基准测试。
A
Airy

最好的方法是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/


这不适用于关联数组和键中有间隙的数组,例如 [1, 2, 4 => 3]
不抱歉,这会起作用。请阅读我提供的文章链接
它不会。考虑一下我上述评论的数组;在我使用您的代码删除值 3 后,数组将是 [1, 2, 3];换句话说,该值没有被删除。需要明确的是,我并不是说它在所有情况下都失败了,只是这个。
array_splice 是最好的方法,unset 删除后不会调整数组索引
T
T.Todua

或者简单地说,手动方式:

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

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


使用 array_splice() 而不是 unset() 也会重新排序数组索引,在这种情况下可能会更好。
R
Roy

在 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));

这太棒了。易于理解,实际使用的箭头函数对我来说是新的。我需要删除基于嵌套值的关联数组的一部分,这对于任何其他答案都是不可能的。我曾使用 foreach() 循环,但这更简洁。
t
tttony
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 )


我不确定这是否更快,因为此解决方案涉及多个函数调用。
仅代码答案在 Stack Overflow 上的价值很低。每个答案都应该包括解释它是如何工作的,或者为什么你觉得它是一个很好的建议,而不是其他技术。
A
Abdur Rehman

你可以做:

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

说明:翻转数组后删除键为401的元素。


如果你想保持状态,你必须非常小心。因为所有未来的代码都必须有值而不是键。
@saadlulu $messages 数组不会被翻转,因为 array_flip() 不会影响原始数组,因此应用上一行后的结果数组将是相同的,只是不需要的结果将被删除。
不确定这是否正确,如果有几个元素的值为 401 怎么办?
这仍将保留密钥。
A
Abdur Rehman

要删除多个值,试试这个:

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

这将比循环输入一次效率低(并且有多种工具可以做到这一点)。假设您正在迭代一个包含 10 个元素的索引数组,并且您想要删除索引 4 和 8 处的元素。这将从 0 迭代到 4,然后取消设置元素 [4],然后将迭代 0 到 8,然后取消设置元素 [ 8]。看看这项技术将如何不必要地检查 [0]、[1]、[2]、[3] 不止一次。出于任何原因,我永远不会使用这种技术,我建议所有研究人员都从这个答案中广泛地诞生。 (这就是我DV的原因)
S
SaidbakR

接受的答案会将数组转换为关联数组,因此,如果您想将其作为接受答案的非关联数组,您可能必须使用 { 1}也是。

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

参考是 here


A
Abdur Rehman

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

您可以将值作为键,这意味着它会立即找到该值。比一遍又一遍地在所有元素中使用搜索要好。

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

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

仅适用于可以转换为字符串的对象。
没有两个值是相同的。通常情况并非如此,尽管在 OP 情况下,它似乎是。
K
Koushik Das

PHP 7.4 或以上

function delArrValues(array $arr, array $remove) {
    return array_filter($arr, fn($e) => !in_array($e, $remove));
};

所以,如果你有数组

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

并且您想从 $messages 数组中删除两个 3, 312,您可以这样做

delArrValues($messages, [3, 312])

它会回来

[401, 1599]

最好的部分是您可以轻松过滤多个值,即使同一值多次出现。


请注意,array_filter 版本的扩展形式可以用于旧版本的 php,例如: ` array_filter( $arr, function($arg) use ($black_list) { return !in_array($arg, $black_list) ; } ); `
A
Abdur Rehman

借用 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;
});

这不是重新发明过滤器吗? php.net/manual/en/function.array-filter.php
确实是的。正如我在帖子中已经说过的“甚至更好:(因为这为我们提供了更好的语法,可以像 array_filter 一样使用)”。有时你真的只需要将函数拒绝作为下划线,它实际上正好与过滤器相反(你需要用尽可能少的代码来获得它)。这就是函数正在做的事情。这是拒绝值的简单方法。
A
Abdur Rehman

我知道这根本没有效率,但简单、直观且易于阅读。因此,如果有人正在寻找一个不那么花哨的解决方案,它可以扩展为使用更多值或更具体的条件.. 这是一个简单的代码:

$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

A
Abdur Rehman

使用 or 运算符的单行:

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

A
Abdur Rehman

根据您的要求“每个值只能存在一次”,如果您只想在数组中保留唯一值,那么 array_unique() 可能就是您要寻找的。

输入:

$input = array(4, "4", "3", 4, 3, "3");
$result = array_unique($input);
var_dump($result);

结果:

array(2) {
  [0] => int(4)
  [2] => string(1) "3"
}

这篇文章绝不会回答 OP 的问题。这是另一个问题的正确答案。 (这就是我DV的原因)
这个答案与问题无关
a
algo

我认为最简单的方法是使用带有 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)
}

f
fico7489

这是一个简单但可以理解的解决方案:

$messagesFiltered = [];
foreach ($messages as $message) {
    if (401 != $message) {
        $messagesFiltered[] = $message;
    }
}
$messages = $messagesFiltered;