【问题标题】:Splatpacking versus array_values() to re-index an array with numeric keysSplatpacking 与 array_values() 使用数字键重新索引数组
【发布时间】:2023-03-06 18:02:01
【问题描述】:

从 PHP7.4 开始,有一种新的可用技术可以用数字键重新索引数组。

我将其称为“array re-packing”或者类似“splatpacking”之类的有趣的东西。简单的过程涉及使用 splat 运算符 (...) - 也称为“扩展运算符” - 解包一个数组,然后通过“对称数组解构”用第一级元素填充一个新数组。

比较代码:(Demo)

$array = [2 => 4, 5 => 3, "3" => null, -10.9 => 'foo'];

var_export(array_values($array));
var_export([...$array]);

两者都会输出:

array (
  0 => 4,
  1 => 3,
  2 => NULL,
  3 => 'foo',
)

同样,splatpacking 技术仅限于带有数字键的数组,因为 splat 运算符会阻塞其他任何内容,并且只能在 PHP7.4 及更高版本中才能将解压后的值直接写入数组。

由于这两种技术在排位赛中提供相同的输出,我应该什么时候使用一种而不是另一种?

请注意,这不是关于如何重新索引键,而是比较 array_values() 与新可用技术。

这不同于:

以及其他数十个询问如何重新索引数组的旧页面。

【问题讨论】:

  • 我认为这是一段时间以来更有趣的 PHP 问题之一,尤其是因为它不是特定于框架的。这让我很好奇,如果它总是更慢,那么 splatpacking 是为了什么。只有语法糖?与采用展开运算符的其他语言保持一致?
  • 这个问题看起来是“研究不足”、“不清楚”还是“对 Stack Overflow 来说是多余的”?那为什么它有一个负数?复仇,为什么?

标签: php arrays reindex argument-unpacking php-7.4


【解决方案1】:

当重新索引一个 450,000 元素的数组时,它的第一个元素未设置...

array_values() 的速度始终是 splatpacking 的两倍。

$array = range(0, 450000);
unset($array[0]);

Benchmark script

样本输出:

Duration of array_values: 15.328378677368
Duration of splat-pack: 29.623107910156

就性能而言,您应该始终使用array_values()。这是函数调用技术比非函数调用技术更有效的一种情况。


我认为 splatpacking 技术获胜的唯一情况是,如果您是 CodeGolfer -- 13 个字符对 5 个字符。

【讨论】:

    【解决方案2】:

    这两种方法之间存在性能差异(如the other answer 所示),但这不是这两种方法之间的主要区别。毕竟你应该记住the famous quote

    过早的优化是万恶之源 - DONALD E. KNUTH

    可能在下一个 PHP 版本中,splat 运算符得到了一些性能优化,它会比array_values() 更快。除非您真的需要从代码中榨取最大的性能,否则我建议您不要担心重新索引数百万个值所需的时间。相反,让我们考虑一下这两种方法有什么共同点或没有什么共同点。

    1. Splat 运算符只能使用数字索引。如果您的数组包含一个字符串键(甚至是一个空字符串),那么 splat 运算符将阻塞并抛出异常:

      致命错误:未捕获的错误:无法使用字符串键解包数组

      如果你想用数字索引重新索引你的数组,那么更安全的选择是使用array_values()。它适用于数值和关联数组。

    2. 在某些情况下,您可能需要将array_value 作为回调传递。如果您想对 splat 运算符执行相同操作,则需要将其包装在闭包中,例如fn($arr) => [...$arr]。使用'array_values' 可能是一个更简单、更清洁的解决方案。例如,如果您想重新索引多维数组(只有数字键),您有以下两个选项:

      $array = [range(0, 10), range(15,25)];
      unset($array[0][1], $array[1][5]);
      
      $reindex_array = array_map('array_values', $array);
      // or
      $reindex_array = array_map(fn($arr) => [...$arr], $array);
      

      当然,这完全取决于你,你喜欢哪种方法。

    3. array_values() 不适用于生成器/迭代器。如果你想解压一个生成器,你可以使用 splat 操作符。例如:

      function arrGen() {
          for($i = 11; $i < 15; $i++) {
              yield $i**2 => $i;
          }
      }
      
      $it = arrGen();
      $reindexed_array = [...$it];
      
    4. Splat 运算符方式不仅允许您重新索引数组,还可以预先或附加额外的值。您还可以将两个数组合并为 1。它比 array_values() 更健壮。例如:

      $arr = ['someValue', 2=> 'Not 2', 3];
      $r1 = ['I am number 1!', ...$arr];
      
      var_dump($r1);
      

    可能在更多情况下一种方法胜过另一种方法。最后,由开发人员根据情况决定何时使用哪个选项。

    【讨论】:

      猜你喜欢
      • 2012-05-18
      • 2013-11-12
      • 2010-10-28
      • 1970-01-01
      • 1970-01-01
      • 2016-05-10
      • 2020-12-27
      • 2014-10-06
      相关资源
      最近更新 更多