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


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

คำตอบ:


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

เตือนว่า:

  • ในรุ่น PHP ก่อน 7.3 จะทำให้เกิดข้อผิดพลาดร้ายแรงหาก$bเป็นอาร์เรย์ว่างเปล่าหรือไม่สามารถผ่านได้เช่นไม่ใช่อาร์เรย์
  • ใน PHP 7.3 คำเตือนจะเพิ่มขึ้นหาก$bไม่สามารถข้ามผ่านได้

คำใดที่ใช้สำหรับไวยากรณ์ดังกล่าว (เช่นใน JS เรียกว่าตัวดำเนินการแพร่กระจาย) หรือคุณสามารถให้ลิงก์ไปยังเอกสารได้หรือไม่
โหระพา

3
@basil คุณจะพบ...ทั่วไปเรียกว่าsplat operatorใน php
mickmackusa

คำตอบที่มีประโยชน์มากที่สุดเมื่อค้นหาวิธีง่ายๆในการผนวกอาร์เรย์ให้กับตัวเองโดยไม่ต้องแก้ไของค์ประกอบใด ๆ ก่อนหน้านี้
Daniel Böttner

1
array_pushยอมรับอาร์กิวเมนต์เดี่ยวตั้งแต่ php 7.3 ซึ่งป้องกันข้อผิดพลาดด้วยอาร์เรย์ที่ว่างเปล่า
vctls

อันที่จริงนี่เป็นวิธีที่สง่างามและมีประสิทธิภาพที่สุด ขอบคุณ
Hassan Ali Salem

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 Baker

2
@ MarkBaker ว้าว! ฉันไม่รู้ว่ามีประวัติแก้ไข! ขออภัยเกี่ยวกับสิ่งนั้นและขอขอบคุณการเปลี่ยนแปลงครั้งนี้มีมากและป้องกันผู้ดูแลไม่ให้ใส่คำเข้าไปในปากคนฉันเคยรู้สึกเหมือนคำถามบางคำถามถูกลบล้างและความคิดเห็นของพวกเขาถูกทำให้เป็นโมฆะโดยเนื้อหาถูกลบ / แก้ไข ประวัติการแก้ไขฉันแน่ใจว่า
ตามใจ

21

มันเป็นโพสต์ที่ค่อนข้างเก่า แต่ฉันต้องการเพิ่มบางอย่างเกี่ยวกับการผนวกหนึ่งอาร์เรย์ลงในอีกอัน:

ถ้า

  • หนึ่งหรือทั้งสองอาร์เรย์มีคีย์เชื่อมโยง
  • กุญแจของอาร์เรย์ทั้งสองนั้นไม่สำคัญ

คุณสามารถใช้ฟังก์ชันอาร์เรย์ดังนี้:

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

array_merge ไม่รวมคีย์ตัวเลขดังนั้นมันจึงผนวกค่าทั้งหมดของ $ appendArray ในขณะที่ใช้ฟังก์ชั่น PHP พื้นเมืองแทน foreach-loop มันควรจะเร็วขึ้นในอาร์เรย์ที่มีองค์ประกอบจำนวนมาก

เพิ่มเติม 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] => int (1) [4] => int (2) [5] => int (3) [6] => int (4)}

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

อาร์เรย์ (3) {[0] => int (1) [1] => int (4) [3] => int (3)}


1
สิ่งนี้ควรมีข้อได้เปรียบจากการปล่อยให้อินพุตอาร์เรย์ไม่ถูกแตะต้อง
Jon Surrell

1
ใช่ปลอดภัยกว่าในกรณีที่จะแตก array_values ​​เพื่อให้คุณไม่รวมเข้ากับคีย์เดียวกัน
Gabriel Rodriguez

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

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 ไม่ใช่คำตอบที่ตรงกับเกณฑ์ของ 'ไม่ใช่ array_push' ในคำถามมันเป็นหนึ่งบรรทัดและมีประสิทธิภาพสูงสุดทุกประการฉันคิดว่าคำถามถูกถามก่อนไวยากรณ์ ... เป็นตัวเลือก

UPDATE 25/03/2020: ฉันได้อัปเดตการทดสอบที่มีข้อบกพร่องแล้วเนื่องจากตัวแปรไม่ได้ถูกรีเซ็ต ที่น่าสนใจ (หรือสับสน) ตอนนี้ผลลัพธ์แสดงว่าเป็นแบบทดสอบ 1 ที่เร็วที่สุดซึ่งช้าที่สุดจาก 0.008392 ถึง 0.002717! สิ่งนี้สามารถลงไปที่การอัพเดต PHP เท่านั้นเนื่องจากจะไม่ได้รับผลกระทบจากข้อบกพร่องในการทดสอบ

ดังนั้นเทพนิยายยังคงดำเนินต่อไปฉันจะเริ่มใช้ array_merge ต่อจากนี้ไป!


2
คุณไม่ได้รีเซ็ตอาร์เรย์ 1 ก่อนการทดสอบแต่ละครั้งดังนั้นการทดสอบแต่ละรายการมีรายการมากกว่า 50,000 รายการก่อนหน้า
Dakusan

น่าทึ่งหลังจากหลายปีที่ผ่านมาคุณเป็นคนแรกที่จะมารับเรื่องนี้ขอบคุณฉันจะทำการทดสอบซ้ำในไม่ช้า :)
Jamie Robinson

5

ตั้งแต่ PHP 7.4คุณสามารถใช้... ผู้ประกอบการ สิ่งนี้เป็นที่รู้จักกันว่าตัวดำเนินการเครื่องหมายในภาษาอื่น ๆ รวมถึงทับทิม

$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 array_mergeนั่นไม่เพียงเพราะตัวดำเนินการสีแดงเป็นโครงสร้างภาษาในขณะที่ array_merge เป็นฟังก์ชัน แต่ยังเป็นเพราะการเพิ่มประสิทธิภาพเวลาในการคอมไพล์สามารถดำเนินการสำหรับอาร์เรย์คงที่

ยิ่งกว่านั้นเราสามารถใช้ไวยากรณ์ตัวดำเนินการเครื่องหมายได้ทุกที่ในอาร์เรย์เนื่องจากสามารถเพิ่มองค์ประกอบปกติก่อนหรือหลังตัวดำเนินการเครื่องหมายได้

$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()ดำเนินการกับการอ้างอิงถึงอาร์เรย์ (อาร์กิวเมนต์ที่ 1) และใส่ค่าอาร์เรย์ (อาร์กิวเมนต์ที่ 4) แทนรายการของค่าที่เริ่มต้นจากอาร์กิวเมนต์ที่สองและจำนวนของอาร์กิวเมนต์ที่ 3 เมื่อเราตั้งค่าอาร์กิวเมนต์ที่สองเป็นจุดสิ้นสุดของแหล่งที่มาของอาร์เรย์และที่ 3 เป็นศูนย์เราจะเพิ่มค่าของอาร์กิวเมนต์ที่ 4 ให้กับอาร์กิวเมนต์ที่ 1


คุณควรมีคำอธิบายบางอย่างสำหรับผู้ที่ไม่ปฏิบัติตามเวทย์มนตร์ต่อเนื่องที่ไม่ลบออก
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 loop เร็วกว่า array_merge เพื่อเพิ่มค่าต่อท้ายอาร์เรย์ที่มีอยู่ดังนั้นให้เลือก loop แทนถ้าคุณต้องการเพิ่มอาร์เรย์ที่ส่วนท้ายของอีกอัน

// 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

1
คุณแน่ใจหรือว่าจะเปรียบเทียบคีย์ กล่าวว่าเอกสาร (เหมืองของการเน้น): "ถ้าอาร์เรย์อินพุตมีคีย์สตริงเหมือนกันดังนั้นค่าในภายหลังสำหรับคีย์นั้นจะเขียนทับคีย์ก่อนหน้านี้อย่างไรก็ตามหากอาร์เรย์มีคีย์ตัวเลขค่าในภายหลังจะไม่เขียนทับต้นฉบับ ค่า แต่จะต่อท้าย ". คุณแน่ใจหรือว่ากุญแจของคุณไม่ได้เป็นจริง'0' => 'a'... แทนที่จะเป็น0 => 'a'?
Piskvor ออกจากอาคาร

@Piskvor ไม่มีความแตกต่างระหว่าง '0' และ 0 สำหรับคีย์
Gordon

สิทธิ์ของกอร์ดอน ความสำคัญอยู่ที่คีย์ตัวเลข (ตรงข้ามกับคีย์จำนวนเต็ม )
netcoder

1
@Gordon: อ่าคุณพูดถูก - นั่นคือสิ่งที่ฉันจะนึกถึงสองสิ่งในคราวเดียว php.net/manual/en/language.operators.array.phpเป็นเอกสารสำหรับarray + array
Piskvor ออกจากอาคาร
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.