【问题标题】:PHP array delete by value (not key)PHP数组按值删除(不是键)
【发布时间】:2013-06-19 15:01:36
【问题描述】:

我有一个PHP数组如下:

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

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

我正在寻找执行此任务的最简单函数。

【问题讨论】:

标签: php arrays


【解决方案1】:

使用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。 (编辑-你明白了)
  • 请注意,这不会重置数组键。
【解决方案2】:

嗯,从数组中删除一个元素基本上只是将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)。
【解决方案3】:

一种有趣的方式是使用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() 可以进行搜索。
【解决方案4】:

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

$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+

【讨论】:

    【解决方案5】:
    $fields = array_flip($fields);
    unset($fields['myvalue']);
    $fields = array_flip($fields);
    

    【讨论】:

    • 这仅适用于您的数组不包含除您要删除的值之外的重复值。
    • 也许吧,但我会使用专门设计的函数,而不是仅仅作为一个基本用于其他用途的函数的幸运副作用。它还会使您的代码不那么透明。
    • 消息指出“每个值只能存在一次”,这应该有效。如果张贴者使用了 smae 变量名并添加了一些解释,那就太好了
    • 显然,与选定的解决方案相比,这是最快的,我做了小基准测试。
    【解决方案6】:

    最好的方法是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 删除后不会调整数组索引
    【解决方案7】:

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

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

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

    【讨论】:

    • 使用array_splice() 而不是unset() 也会重新排序数组索引,在这种情况下可能会更好。
    【解决方案8】:

    在 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() 循环,但这更简洁。
    【解决方案9】:
    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 上的价值很低。每个答案都应说明它是如何工作的,或者为什么您认为它是比其他技术更好的建议。
    【解决方案10】:

    你可以这样做:

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

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

    【讨论】:

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

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

    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 的原因)
    【解决方案12】:

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

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

    $messages=array();   
    $messages[312] = 312;    
    $messages[401] = 401;   
    $messages[1599] = 1599;   
    $messages[3] = 3;    
    
    unset($messages[3]); // no search needed
    

    【讨论】:

    • 仅适用于可以转换为字符串的对象。
    • 而且没有两个值是相同的。通常情况并非如此,尽管在 OP 的情况下,它似乎是。
    【解决方案13】:

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

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

    参考是here

    【讨论】:

      【解决方案14】:

      借用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 一样使用)”。有时您真的只需要将函数拒绝作为下划线,它实际上与过滤器相反(并且您需要使用尽可能少的代码来获得它)。这就是函数正在做的事情。这是拒绝值的简单方法。
      【解决方案15】:

      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]
      

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

      【讨论】:

        【解决方案16】:

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

        $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
        

        【讨论】:

          【解决方案17】:

          使用or 运算符的单行代码:

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

          【讨论】:

            【解决方案18】:

            根据您的要求“每个值只能存在一次”,如果您只想在数组中保留唯一值,那么 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 的原因)
            • 这个答案与问题无关
            【解决方案19】:

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

            【讨论】:

              【解决方案20】:

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

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-05-05
                • 1970-01-01
                • 2017-06-23
                • 1970-01-01
                • 2014-03-21
                相关资源
                最近更新 更多