PHP将一个数组添加到另一个数组中(不使用array_push或+)

376

如何将一个数组追加到另一个数组而不比较它们的键?

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

26
array_merge($a, $b) 至少在 PHP 5+ 中应该正好能够满足您的需求。 - tloach
1
在PHP中用于数组的加法运算符 - Gordon
6
你发布的所有输出结果都不是由array_merge();产生的,而array_merge();的输出结果应该正好符合你的需求:print_r(array_merge($a,$b)); // 输出结果 => Array ( [0] => a [1] => b [2] => c [3] => d )。请注意不要改变原意,并使翻译内容更加通俗易懂。 - acm
4
我完全不同意“append”这个术语。实际上,“append”的意思是将一个数组的项作为元素添加到另一个(目标)数组中,而目标数组可能已经有一些元素,因此会改变目标数组。而“merge”则会分配一个新的数组,将两个数组的元素复制过去。相比之下,“append”实际上是在不需要额外的内存分配的情况下重用目标数组中的元素。 - tishma
所有方法都在页面[PHP-docs]的“用户贡献注释”[1]中描述:https://www.php.net/manual/ru/function.array-push.php - Михаил
11个回答

554

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具有相同的键,则不会发生任何事情。


29
如果您的键不是数字而是字符串,请小心。根据文档:如果输入数组具有相同的字符串键,则该键的后续值将覆盖先前的值。 - Dusan Plavak
2
请使用现代的splat运算符,如@bstoney的答案所示https://dev59.com/bW855IYBdhLWcg3wj1MS#37065301 - basil

162

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

但需要注意的是:在PHP 7.3之前的版本中,如果$b是一个空数组或者不可遍历的(如非数组),那么会导致致命错误;而在PHP 7.3中,如果$b不可遍历,则会提出警告信息。


这种语法用什么术语来描述?(例如,在JS中,它被称为扩展运算符)或者你能提供文档链接吗? - basil
8
@basil,你会发现在PHP中 ... 通常被称为 splat operator - mickmackusa
3
在寻找一种简单的方法将一个数组追加到其自身而不覆盖任何先前元素时,最有用的答案。 - Daniel Böttner
1
自 PHP 7.3 开始,array_push 只接受一个参数,这可以避免空数组出现错误。 - vctls
2
一个小提示:这不适用于关联数组。(致命错误:无法使用字符串键解包数组) - Turab
使用关联数组会抛出以下错误(PHP 8.1):"array_push() 不接受未知的命名参数"。 - Écio Silva

41

为什么不使用

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

为什么您不想使用这个正确的内置方法呢?


OP在哪里说他“不想使用”array_merge()函数...? - KittenCodings
6
请阅读问题的“编辑历史”……原问题标题为“PHP append one array to another (not array_merge or array_push)”,后来修改为“PHP append one array to another (not array_merge or +)”,最终变成现在的标题。 - Mark Baker
2
@MarkBaker 哇!我不知道SO有编辑历史记录!对此感到抱歉,谢谢你,这改变了很多事情,也在某种程度上防止了版主替别人说话。以前我觉得一些问题被篡改和评论被删除/编辑后无效了,但我想大多数人可能不会读编辑历史记录,但从现在开始我肯定会读的。 - KittenCodings

30

这是一篇相当古老的文章,但我想补充一下如何将一个数组追加到另一个数组中:

如果

  • 一个或两个数组具有关联键
  • 两个数组的键不重要

您可以使用以下数组函数:

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

array_merge不会合并数字键,因此它会追加$appendArray的所有值。使用原生php函数而不是foreach循环,在具有许多元素的数组上应该更快。

附加 2019-12-13:自PHP 7.4以来,有可能使用数组扩展运算符的方式追加或预先添加数组:

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


1
这样做还有一个好处,就是不会改变输入数组的内容。 - Jon Surrell
1
是的,为了避免合并到相同的键中,最好提取array_values。 - Gabriel Rodriguez
非常老的答案,那么你如何解决键的问题? - Mike Kormendy

20
<?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
)

参考源代码


你的回答非常详细,对我来说很重要的是这个例子,它指出当键相同时(对于关联数组),array_merge 可能会与那些仅仅从名称上理解它的人的期望相反。 - Ajowi

15

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

// Test 1 (array_merge)
$array1 = $array2 = array_fill(0, 50000, 'aa');
$start = microtime(true);
$array1 = array_merge($array1, $array2);
printf("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;
}
printf("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);
printf("Test 3: %.06f\n", microtime(true) - $start);

这将产生:

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

我相信从PHP 7开始,第三种方法是一个明显更好的选择,因为foreach 循环现在的行为是复制正在迭代的数组。

虽然第三种方法严格来说并不是问题中“不使用array_push”的答案,但它只有一行,而且在所有方面都具有最高性能,我认为这个问题是在...语法成为一个选项之前提出的。

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

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


3
每次测试之前你没有重置数组1,所以每个测试都比之前多了50000个项目。 - Dakusan
多年后,您是第一个提出这个问题的人,非常感谢,我会很快重新测试 :) - Jamie Robinson
你只需要调用一次array_merge()函数。但是如果你有一个大数组,需要多次追加小数组呢? - rick-rick-rick
我猜(我没有测试)在这种情况下连接可能更好,因为它可以避免内存复制。然而,如果有什么我从PHP性能优化/测量中学到的东西,那就是很难确定,而且会随着更新而变化。我选择看起来最好的那种方式 :) - Jamie Robinson

14

对于大数组,最好不要使用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

任何人的代码中都不应该存在“echo sprintf()”。只需写“printf()”,不要加上“echo”。 - mickmackusa

10
自PHP 7.4以来,您可以使用“...操作符”。这在其他语言中也称为“展开操作符”,包括Ruby。
$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"
}
的性能应该比更好。这不仅是因为是语言结构而是函数,还因为编译时优化对于常量数组可以具有优异性能。
此外,我们可以在数组中的任何位置使用语法,因为普通元素可以在之前或之后添加。
$arr1 = [1, 2, 3];
$arr2 = [4, 5, 6];
$arr3 = [...$arr1, ...$arr2];
$arr4 = [...$arr1, ...$arr3, 7, 8, 9];

Splat 在 php5.6 中被推荐使用 https://dev59.com/bW855IYBdhLWcg3wj1MS#37065301 - mickmackusa
谢谢。这样更加优雅。 - JuliaJ

3
在 PHP7 之前,您可以使用以下方法:
array_splice($a, count($a), 0, $b);

array_splice() 是一个与数组(第1个参数)相关的函数,它将以第2个参数和第3个参数为起点的一系列数值替换成第4个参数的值。当我们将第2个参数设置为源数组的末尾,并将第3个参数设置为零时,我们将第4个参数的值追加到第1个参数中。


0

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

$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

希望这有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接