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


278

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

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

16
array_merge ($a, $b)至少可以在PHP 5+上完全满足您的要求。
10年


6
任何输出的您发布来自array_merge();输出的array_merge();应该是exaclty你需要什么:print_r(array_merge($a,$b)); // outputs => Array ( [0] => a [1] => b [2] => c [3] => d )
ACM

2
我完全不同意“附加”一词。追加实际上意味着一个数组的项成为另一个(目标)数组的元素,该数组可能已经具有某些元素,因此更改了目标数组。合并分配一个新的数组和两个数组的COPIES元素,而附加实际上意味着重新使用目标数组元素而无需额外的内存分配。
tishma 2014年

Answers:


424

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,则不会执行任何操作。


16
请小心,如果您的键不是数字而是字符串,则来自doc:如果输入数组具有相同的字符串键,则该键的后一个值将覆盖前一个键
Dusan Plavak

或使用现代splat运算符作为@bstoney答案stackoverflow.com/a/37065301/962634
罗勒

76

在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中,它称为“传播运算符”)或您是否可以提供文档链接?
罗勒

3
@basil您会发现...通常splat operator在php中称为。
mickmackusa

寻找一种简单的方法将数组追加到自身而不覆盖任何先前的元素时,这是最有用的答案。
DanielBöttner19年

1
array_push自php 7.3起接受单个参数,以防止出现空数组错误。
vctls

实际上,这是最优雅,最有效的方法。谢谢
哈桑·阿里·塞勒姆

33

为什么不使用

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

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


OP在哪里说他“不想使用” array_merge()...?
KittenCodings

3
@KittenCodings-阅读问题的“编辑历史记录”……原始问题的标题为PHP append one array to another (not array_merge or array_push)……随后PHP append one array to another (not array_merge or +)更改为当前问题,然后更改为当前标题
Mark Ba​​ker

2
@MarkBaker哇!我不知道SO有编辑记录!对此感到抱歉,谢谢,这发生了很大变化,并在一定程度上阻止了主持人向人们发表言论。我以前觉得有些问题被污损了,他们的评论被内容删除/编辑了,尽管我想大多数人可能不会阅读编辑历史,我确信从现在开始
KittenCodings'Aug

21

这是一篇很老的文章,但是我想添加一些关于将一个数组追加到另一个数组的内容:

如果

  • 一个或两个数组具有关联键
  • 两个数组的键都没有关系

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

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

array(4){[1] => int(1)[4] => int(2)[5] => int(3)[6] => int(4)}

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

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


1
这还应具有不影响输入数组的优点。
乔恩·瑟雷尔

1
是的,以防万一提取array_values以便不合并到相同的键中,这样比较安全。
加布里埃尔·罗德里格斯

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

参考源代码


12

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

对我来说就像是一种魅力,这种方法的速度快了50倍。
luttkens's

9

根据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循环现在起作用了,这是是复制要迭代的数组的副本。

尽管方法3并非严格回答问题中“ not array_push”的标准,但它是一行,并且在所有方面都具有最高的性能,我认为在...语法成为选项之前就提出了问题。

更新25/03/2020:我已经更新了测试,该测试存在缺陷,因为未重置变量。有趣(或令人困惑)的结果现在显示为测试1最快,最慢,从0.008392变为0.002717!这只能取决于PHP更新,因为这不会受到测试缺陷的影响。

因此,传奇继续,我将从现在开始使用array_merge!


2
您无需在每次测试前重置array1,因此每个测试比以前多50,000个项目。
Dakusan

这么多年了不起,您是第一个认识我的人,谢谢,我将在近期内进行重新测试:)
Jamie Robinson

5

从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运算符应比array_merge具有更好的性能。这不仅是因为splat运算符是一种语言结构,而array_merge是一个函数,也是因为编译时优化可以对常量数组执行。

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

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

3

在PHP7之前,您可以使用:

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

array_splice()参照数组(第一个参数)进行操作,并将数组(第四个参数)值放在从第二个参数和第三个参数编号开始的值列表的位置。当我们将第二个参数设置为源数组的末尾,第三个参数设置为零时,我们将第四个参数值附加到第一个参数


您应该向那些不遵循不可移除的拼接魔术的人提供一些解释。
mickmackusa

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

希望它的帮助。


0

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

此答案不会给页面带来任何新信息。性能比较是在几年前发布的。
mickmackusa

-4

这个怎么样:

$appended = $a + $b;

1
如我所说,它将比较键,并得出以下结果:Array([0] => a [1] => b)
Danil K 2010年

1
确定它将比较密钥吗?文档说(重点是我的):“如果输入数组具有相同的字符串键,则该键的后一个值将覆盖前一个键。但是,如果数组包含数字键,则后一个值将不覆盖原始键。值,但将被附加。 ”。您确定您的钥匙实际上'0' => 'a'不是...而不是0 => 'a'
Piskvor于

@Piskvor键的'0'和0之间没有区别。
戈登

戈登的权利。重点是数字键(与整数键相反)。
netcoder

1
@戈登:嗯,你是对的-这就是我想到的两件事。php.net/manual/en/language.operators.array.php是的文档array + array
Piskvor在
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.