PHP 将一个数组附加到另​​一个数组(不是 array_push 或 +)

Posted

技术标签:

【中文标题】PHP 将一个数组附加到另​​一个数组(不是 array_push 或 +)【英文标题】:PHP append one array to another (not array_push or +) 【发布时间】:2011-05-15 05:00:50 【问题描述】:

如何在不比较它们的键的情况下将一个数组附加到另​​一个数组?

$a = array( 'a', 'b' );
$b = array( 'c', 'd' );

最后应该是:Array( [0]=>a [1]=>b [2]=>c [3]=>d ) 如果我使用[]array_push 之类的内容,则会导致以下结果之一:

Array( [0]=>a [1]=>b [2]=>Array( [0]=>c [1]=>d ) )
//or
Array( [0]=>c [1]=>d )

它应该是一些东西,这样做,但以更优雅的方式:

foreach ( $b AS $var )
    $a[] = $var;

【问题讨论】:

array_merge ($a, $b) 应该完全符合您的要求,至少使用 php 5+。 (相关) + Operator for Array in PHP 您发布的所有输出都不是来自array_merge(); array_merge(); 的输出应该是您所需要的:print_r(array_merge($a,$b)); // outputs => Array ( [0] => a [1] => b [2] => c [3] => d ) 我完全不同意“追加”这个词。追加实际上意味着一个数组的项目成为另一个(目标)数组的元素,该数组可能已经有一些元素,因此改变了目标数组。 Merge 分配一个新数组并复制两个数组的元素,而 append 实际上意味着重用目标数组元素而不需要额外的内存分配。 所有方法都在“用户贡献的笔记”[1]的页面[PHP-docs]中描述:php.net/manual/ru/function.array-push.php 【参考方案1】:

array_merge 是优雅的方式:

$a = array('a', 'b');
$b = array('c', 'd');
$merge = array_merge($a, $b); 
// $merge is now equals to array('a','b','c','d');

做类似的事情:

$merge = $a + $b;
// $merge now equals array('a','b')

不会起作用,因为+ 运算符实际上并没有合并它们。如果他们$a$b 有相同的键,它不会做任何事情。

【讨论】:

请注意,如果您的键不是数字而是字符串,来自 doc:如果输入数组具有相同的字符串键,则该键的后一个值将覆盖前一个 或使用现代 splat 运算符作为@bstoney 答案***.com/a/37065301/962634【参考方案2】:

在 PHP 5.6+ 中执行此操作的另一种方法是使用 ... 令牌

$a = array('a', 'b');
$b = array('c', 'd');

array_push($a, ...$b);

// $a is now equals to array('a','b','c','d');

这也适用于任何Traversable

$a = array('a', 'b');
$b = new ArrayIterator(array('c', 'd'));

array_push($a, ...$b);

// $a is now equals to array('a','b','c','d');

警告

在 7.3 之前的 PHP 版本中,如果 $b 是一个空数组或不可遍历,这将导致致命错误,例如不是数组 在 PHP 7.3 中,如果 $b 不可遍历,则会引发警告

【讨论】:

这种语法使用哪个术语? (例如在 JS 中它被称为扩展运算符)或者您可以提供文档链接吗? @basil 你会发现...在php中通常被称为splat operator 寻找一种简单的方法将数组附加到自身而不覆盖任何先前元素时最有用的答案。 array_push 从 php 7.3 开始接受单个参数,这可以防止空数组出错。 一点注意:这不适用于关联数组。 (致命错误:无法使用字符串键解压数组)【参考方案3】:

为什么不使用

$appended = array_merge($a,$b); 

你为什么不想使用这个正确的内置方法。

【讨论】:

OP 在哪里说他“不想使用”array_merge()...? @KittenCodings - 阅读问题的“编辑历史”...原来的问题标题为PHP append one array to another (not array_merge or array_push)...随后修改为PHP append one array to another (not array_merge or +),然后更改为当前标题 @MarkBaker 哇!我不知道SO有编辑历史!对此感到抱歉,谢谢,这改变了很多,并且在某种程度上阻止了版主把话放到人们的嘴里,我以前觉得有些问题被污损了,他们的 cmets 因内容被删除/编辑而失效,尽管我想大多数人可能不读编辑历史,我肯定从现在开始【参考方案4】:

这是一篇相当老的帖子,但我想添加一些关于将一个数组附加到另​​一个数组的内容:

如果

一个或两个数组都有关联键 两个数组的键无关紧要

你可以像这样使用数组函数:

array_merge(array_values($array), array_values($appendArray));

array_merge 不会合并数字键,因此它会附加 $appendArray 的所有值。虽然使用原生 php 函数而不是 foreach 循环,但它在包含大量元素的数组上应该更快。

2019-12-13 补充: 从 PHP 7.4 开始,可以使用 Array Spread Operator 方式附加或前置数组:

    $a = [3, 4];
    $b = [1, 2, ...$a];

和以前一样,键可能是这个新功能的问题:

    $a = ['a' => 3, 'b' => 4];
    $b = ['c' => 1, 'a' => 2, ...$a];

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

    $a = [3 => 3, 4 => 4];
    $b = [1 => 1, 4 => 2, ...$a];

数组(4) [1]=> 整数(1) [4]=> 整数(2) [5]=> 整数(3) [6]=> 整数(4)

    $a = [1 => 1, 2 => 2];
    $b = [...$a, 3 => 3, 1 => 4];

数组(3) [0]=> 整数(1) [1]=> 整数(4) [3]=> 整数(3)

【讨论】:

这也应该有保持输入数组不变的优点。 是的,以防万一提取 array_values 这样您就不会合并到相同的键中,这样会更安全。 非常老的答案,那么您如何解决密钥问题?【参考方案5】:
<?php
// Example 1 [Merging associative arrays. When two or more arrays have same key
// then the last array key value overrides the others one]

$array1 = array("a" => "JAVA", "b" => "ASP");
$array2 = array("c" => "C", "b" => "PHP");
echo " <br> Example 1 Output: <br>";
print_r(array_merge($array1,$array2));

// Example 2 [When you want to merge arrays having integer keys and
//want to reset integer keys to start from 0 then use array_merge() function]

$array3 =array(5 => "CSS",6 => "CSS3");
$array4 =array(8 => "javascript",9 => "html");
echo " <br> Example 2 Output: <br>";
print_r(array_merge($array3,$array4));

// Example 3 [When you want to merge arrays having integer keys and
// want to retain integer keys as it is then use PLUS (+) operator to merge arrays]

$array5 =array(5 => "CSS",6 => "CSS3");
$array6 =array(8 => "JAVASCRIPT",9 => "HTML");
echo " <br> Example 3 Output: <br>";
print_r($array5+$array6);

// Example 4 [When single array pass to array_merge having integer keys
// then the array return by array_merge have integer keys starting from 0]

$array7 =array(3 => "CSS",4 => "CSS3");
echo " <br> Example 4 Output: <br>";
print_r(array_merge($array7));
?>

输出:

Example 1 Output:
Array
(
[a] => JAVA
[b] => PHP
[c] => C
)

Example 2 Output:
Array
(
[0] => CSS
[1] => CSS3
[2] => JAVASCRIPT
[3] => HTML
)

Example 3 Output:
Array
(
[5] => CSS
[6] => CSS3
[8] => JAVASCRIPT
[9] => HTML
)

Example 4 Output:
Array
(
[0] => CSS
[1] => CSS3
)

Reference Source Code

【讨论】:

你的回答很透彻;对我来说最重要的例子是,当键相同时(对于关联数组),array_merge 的行为可能与那些简单地以它的名称 为依据的人的预期相反。 感谢@Ajowi 的宝贵反馈。【参考方案6】:

根据 bstoney 和 Snark 的回答,我对各种方法进行了一些测试:

// Test 1 (array_merge)
$array1 = $array2 = array_fill(0, 50000, 'aa');
$start = microtime(true);
$array1 = array_merge($array1, $array2);
echo sprintf("Test 1: %.06f\n", microtime(true) - $start);

// Test2 (foreach)
$array1 = $array2 = array_fill(0, 50000, 'aa');
$start = microtime(true);
foreach ($array2 as $v) 
    $array1[] = $v;

echo sprintf("Test 2: %.06f\n", microtime(true) - $start);

// Test 3 (... token)
// PHP 5.6+ and produces error if $array2 is empty
$array1 = $array2 = array_fill(0, 50000, 'aa');
$start = microtime(true);
array_push($array1, ...$array2);
echo sprintf("Test 3: %.06f\n", microtime(true) - $start);

产生:

Test 1: 0.002717 
Test 2: 0.006922 
Test 3: 0.004744

原创:我相信从 PHP 7 开始,方法 3 是一个明显更好的替代方案,因为 foreach loops now act 的方式是复制被迭代的数组。

虽然方法 3 并不是对问题中“非 array_push”标准的严格回答,但它是一行并且在所有方面都具有最高的性能,我认为这个问题是在 ... 语法之前提出的一个选项。

2020 年 3 月 25 日更新: 我已经更新了有缺陷的测试,因为变量没有被重置。有趣(或令人困惑)结果现在显示测试 1 是最快的,它是最慢的,从 0.008392 变为 0.002717!这只能归结为 PHP 更新,因为这不会受到测试缺陷的影响。

所以,传奇还在继续,我将从现在开始使用 array_merge!

【讨论】:

您不会在每次测试之前重置 array1,因此每次测试都比前一次多 50,000 个项目。 太棒了这么多年你是第一个接我的人,谢谢,我会尽快重新测试:)【参考方案7】:

对于大数组,最好不使用array_merge进行连接,以避免内存复制。

$array1 = array_fill(0,50000,'aa');
$array2 = array_fill(0,100,'bb');

// Test 1 (array_merge)
$start = microtime(true);
$r1 = array_merge($array1, $array2);
echo sprintf("Test 1: %.06f\n", microtime(true) - $start);

// Test2 (avoid copy)
$start = microtime(true);
foreach ($array2 as $v) 
    $array1[] = $v;

echo sprintf("Test 2: %.06f\n", microtime(true) - $start);


// Test 1: 0.004963
// Test 2: 0.000038

【讨论】:

【参考方案8】:

自 PHP 7.4 起,您可以使用 ... 运算符。这在其他语言(包括 Ruby)中也称为 splat 运算符

$parts = ['apple', 'pear'];
$fruits = ['banana', 'orange', ...$parts, 'watermelon'];
var_dump($fruits);

输出

array(5) 
    [0]=>
    string(6) "banana"
    [1]=>
    string(6) "orange"
    [2]=>
    string(5) "apple"
    [3]=>
    string(4) "pear"
    [4]=>
    string(10) "watermelon"

Splat operator 应该比 array_merge 有更好的性能。这不仅是因为 splat 运算符是一种语言结构,而 array_merge 是一个函数,还因为编译时优化可以对常量数组执行。

此外,我们可以在数组中的任何地方使用 splat 运算符语法,因为可以在 splat 运算符之前或之后添加普通元素。

$arr1 = [1, 2, 3];
$arr2 = [4, 5, 6];
$arr3 = [...$arr1, ...$arr2];
$arr4 = [...$arr1, ...$arr3, 7, 8, 9];

【讨论】:

Splat 在 php5.6 ***.com/a/37065301/2943403 中被推荐【参考方案9】:

PHP7之前可以使用:

array_splice($a, count($a), 0, $b);

array_splice() 参考数组(第一个参数)进行操作,并将数组(第四个参数)值代替从第二个参数和第三个参数的数量开始的值列表。当我们将第二个参数设置为源数组的结尾并将第三个参数设置为零时,我们将第四个参数值附加到第一个参数

【讨论】:

【参考方案10】:

如果您想将空数组与现有的新值合并。你必须先初始化它。

$products = array();
//just example
for($brand_id=1;$brand_id<=3;$brand_id++)
  array_merge($products,getByBrand($brand_id));

// it will create empty array
print_r($a);

//check if array of products is empty
for($brand_id=1;$brand_id<=3;$brand_id++)
  if(empty($products))
    $products = getByBrand($brand_id);
  else
    array_merge($products,getByBrand($brand_id));
  

// it will create array of products

希望有帮助。

【讨论】:

【参考方案11】:

foreach 循环比 array_merge 更快地将值附加到现有数组,因此如果要将数组添加到另一个数组的末尾,请选择循环。

// Create an array of arrays
$chars = [];
for ($i = 0; $i < 15000; $i++) 
    $chars[] = array_fill(0, 10, 'a');


// test array_merge
$new = [];
$start = microtime(TRUE);
foreach ($chars as $splitArray) 
    $new = array_merge($new, $splitArray);

echo microtime(true) - $start; // => 14.61776 sec

// test foreach
$new = [];
$start = microtime(TRUE);
foreach ($chars as $splitArray) 
    foreach ($splitArray as $value) 
        $new[] = $value;
    

echo microtime(true) - $start; // => 0.00900101 sec
// ==> 1600 times faster

【讨论】:

这个答案不会给页面带来任何新信息。性能比较是几年前发布的。【参考方案12】:

这个怎么样:

$appended = $a + $b;

【讨论】:

它会比较键,正如我所说的,结果如下:Array ([0] => a [1] => b) 确定它会比较密钥吗?文档说(强调我的):“如果输入数组具有相同的字符串键,那么该键的后面的值将覆盖前一个。但是,如果数组包含数字键,则后面的值不会覆盖原始值,但会被追加。”。您确定您的密钥实际上不是 '0' =&gt; 'a' ... 而不是 0 =&gt; 'a' 吗? @Piskvor 键的 '0' 和 0 没有区别。 戈登说得对。重点是数字键(相对于整数键)。 @Gordon:啊,你是对的——这就是我同时考虑两件事的结果。 php.net/manual/en/language.operators.array.php 是 array + array 的文档

以上是关于PHP 将一个数组附加到另​​一个数组(不是 array_push 或 +)的主要内容,如果未能解决你的问题,请参考以下文章

在JavaScript中将一个数组附加到另​​一个数组[重复]

将嵌套结构中的数组附加到另​​一个嵌套结构中的另一个数组

单击按钮后将名称附加到数组,然后将其发送到另一个视图控制器

将数组列表附加到数组并在 kotlin 中重复此操作

Java对数组进行排序并将其附加到另一个数组中

如何将 Php 数组变量的值复制到另一个数组