PHP nối thêm một mảng vào một mảng khác (không phải mảng_push hoặc +)


278

Làm thế nào để nối một mảng với mảng khác mà không so sánh các khóa của chúng?

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

Cuối cùng, nó sẽ là: Array( [0]=>a [1]=>b [2]=>c [3]=>d ) Nếu tôi sử dụng một cái gì đó như []hoặc array_push, nó sẽ gây ra một trong những kết quả sau:

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

Nó chỉ nên là một cái gì đó, làm điều này, nhưng theo một cách thanh lịch hơn:

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

16
array_merge ($a, $b)nên làm chính xác những gì bạn muốn, ít nhất là với PHP 5+.
tloach


6
không có kết quả nào bạn đăng tải đến từ array_merge();đầu ra array_merge();nên là exaclty những gì bạn cần:print_r(array_merge($a,$b)); // outputs => Array ( [0] => a [1] => b [2] => c [3] => d )
acm

2
Tôi hoàn toàn không đồng ý với thuật ngữ "nối thêm". Nối thực sự có nghĩa là các mục của một mảng trở thành các phần tử của mảng (đích) khác có thể đã có một số phần tử, do đó thay đổi mảng đích. Hợp nhất phân bổ một mảng mới và các phần tử COPIES của cả hai mảng, trong khi chắp thêm thực sự có nghĩa là sử dụng lại các phần tử mảng đích mà không cần cấp phát thêm bộ nhớ.
tishma

Câu trả lời:


424

array_merge là cách thanh lịch:

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

Làm một cái gì đó như:

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

Sẽ không hoạt động, bởi vì +toán tử không thực sự hợp nhất chúng. Nếu họ $acó cùng khóa $b, nó sẽ không làm gì cả.


16
Hãy cẩn thận nếu các khóa của bạn không phải là một số mà là các chuỗi, Từ doc: Nếu các mảng đầu vào có cùng các khóa chuỗi, thì giá trị sau cho khóa đó sẽ ghi đè lên khóa trước
Dusan Plavak 5/2/2016

hoặc sử dụng toán tử splat hiện đại như @bstoney answer stackoverflow.com/a/37065602/962634
húng quế

76

Một cách khác để làm điều này trong PHP 5.6+ là sử dụng ...mã thông báo

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

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

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

Điều này cũng sẽ làm việc với bất kỳ 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');

Một cảnh báo mặc dù:

  • trong các phiên bản PHP trước 7.3, điều này sẽ gây ra lỗi nghiêm trọng nếu $blà một mảng trống hoặc không thể duyệt qua, ví dụ không phải là một mảng
  • trong PHP 7.3, một cảnh báo sẽ được đưa ra nếu $bkhông thể truy cập được

Thuật ngữ nào được sử dụng cho cú pháp như vậy? (Ví dụ: trong JS, nó được gọi là toán tử trải) Hoặc bạn có thể cung cấp liên kết đến tài liệu không?
húng quế

3
@basil bạn sẽ thấy ...thường được gọi là splat operatortrong php.
mickmackusa

Câu trả lời hữu ích nhất khi tìm kiếm một cách đơn giản để nối một mảng vào chính nó mà không ghi đè bất kỳ yếu tố nào trước đó.
Daniel Böttner

1
array_pushchấp nhận một đối số duy nhất kể từ php 7.3, để ngăn lỗi với các mảng trống.
vctls

Thật ra, đây là cách thanh lịch và hiệu quả nhất. cảm ơn
Hassan Ali Salem

33

Tại sao không sử dụng

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

Tại sao bạn không muốn sử dụng phương pháp này, phương thức tích hợp chính xác.


OP nói anh ấy "không muốn sử dụng" Array_merge () ... ở đâu?
KittenCodings

3
@KittenCodings - Đọc "lịch sử chỉnh sửa" của câu hỏi ... câu hỏi ban đầu có quyền PHP append one array to another (not array_merge or array_push)... sau đó được sửa đổi thành PHP append one array to another (not array_merge or +)trước khi đổi thành tiêu đề hiện tại
Mark Baker

2
@MarkBaker Wow! Tôi không biết SO có lịch sử chỉnh sửa! Xin lỗi về điều đó, và cảm ơn, điều này thay đổi rất nhiều và phần nào ngăn người điều hành đưa từ ngữ vào miệng mọi người, trước đây tôi cảm thấy như một số câu hỏi bị xóa và nhận xét của họ bị vô hiệu bởi nội dung bị xóa / chỉnh sửa, mặc dù tôi tưởng tượng hầu hết mọi người có thể không đọc lịch sử chỉnh sửa, tôi chắc chắn sẽ như thế nào từ bây giờ
KittenCodings

21

Đây là một bài viết khá cũ, nhưng tôi muốn thêm một cái gì đó về việc nối thêm một mảng vào một mảng khác:

Nếu

  • một hoặc cả hai mảng có khóa kết hợp
  • các khóa của cả hai mảng không quan trọng

bạn có thể sử dụng các hàm mảng như thế này:

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

Array_merge không hợp nhất các khóa số để nó nối thêm tất cả các giá trị của $ appendArray. Trong khi sử dụng các hàm php gốc thay vì vòng lặp foreach, nó sẽ nhanh hơn trên các mảng có nhiều phần tử.

Bổ sung 2019-12-13: Kể từ PHP 7.4, có khả năng nối thêm hoặc thêm vào mảng theo cách của Toán tử trải rộng mảng:

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

Như trước đây, các khóa có thể là một vấn đề với tính năng mới này:

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

"Lỗi nghiêm trọng: Uncaught Error: Không thể giải nén mảng bằng các phím chuỗi"

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

mảng (4) {[1] => int (1) [4] => int (2) [5] => int (3) [6] => int (4)}

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

mảng (3) {[0] => int (1) [1] => int (4) [3] => int (3)}


1
Điều này cũng có lợi thế là không để lại các mảng đầu vào.
Jon Surrell

1
Có, sẽ an toàn hơn trong trường hợp trích xuất mảng_values ​​để bạn không hợp nhất vào cùng một khóa.
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));
?>

Đầu ra:

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
)

Mã nguồn tham khảo


12

Đối với mảng lớn, tốt hơn là nối mà không có Array_merge, để tránh sao chép bộ nhớ.

$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

Hoạt động như một cơ duyên, đối với tôi cách tiếp cận này nhanh hơn 50 lần.
luttkens

9

Theo dõi câu trả lời của bstoney và Snark, tôi đã thực hiện một số thử nghiệm về các phương pháp khác nhau:

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

Sản xuất:

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

NGUỒN GỐC: Tôi tin rằng từ PHP 7, phương thức 3 là một sự thay thế tốt hơn đáng kể do cách các vòng lặp foreach hiện hành động , đó là tạo một bản sao của mảng được lặp đi lặp lại.

Mặc dù phương pháp 3 không hoàn toàn là một câu trả lời cho các tiêu chí 'không phải mảng_push' trong câu hỏi, nhưng đây là một dòng và hiệu suất cao nhất trong tất cả các khía cạnh, tôi nghĩ rằng câu hỏi đã được hỏi trước khi ... cú pháp là một tùy chọn.

CẬP NHẬT 25/03/2020: Tôi đã cập nhật bài kiểm tra bị lỗi khi các biến không được đặt lại. Thật thú vị (hoặc khó hiểu) các kết quả hiện cho thấy thử nghiệm 1 là nhanh nhất, trong đó chậm nhất, đã đi từ 0,008392 đến 0,002717! Điều này chỉ có thể được cập nhật xuống PHP, vì điều này sẽ không bị ảnh hưởng bởi lỗ hổng thử nghiệm.

Vì vậy, câu chuyện tiếp tục, tôi sẽ bắt đầu sử dụng Array_merge kể từ bây giờ!


2
Bạn không đặt lại mảng1 trước mỗi thử nghiệm, vì vậy mỗi thử nghiệm có thêm 50.000 mặt hàng so với trước đó.
Dakusan

Thật tuyệt vời sau bao nhiêu năm bạn là người đầu tiên đón tôi về điều này, cảm ơn bạn, tôi sẽ làm lại một thời gian ngắn :)
Jamie Robinson

5

Kể từ PHP 7.4, bạn có thể sử dụng toán tử ... . Đây còn được gọi là toán tử splat trong các ngôn ngữ khác, bao gồm cả Ruby.

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

Đầu ra

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

Toán tử Splat nên có hiệu năng tốt hơn mảng_merge . Điều đó không chỉ bởi vì toán tử splat là một cấu trúc ngôn ngữ trong khi Array_merge là một hàm, mà còn bởi vì tối ưu hóa thời gian biên dịch có thể được thực hiện cho các mảng không đổi.

Hơn nữa, chúng ta có thể sử dụng cú pháp toán tử splat ở mọi nơi trong mảng, vì các phần tử bình thường có thể được thêm vào trước hoặc sau toán tử splat.

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

3

Trước PHP7 bạn có thể sử dụng:

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

array_splice()hoạt động với tham chiếu đến mảng (đối số thứ 1) và đặt các giá trị mảng (đối số thứ 4) thay cho danh sách các giá trị được bắt đầu từ đối số thứ 2 và số của đối số thứ 3. Khi chúng ta đặt đối số thứ 2 là cuối mảng nguồn và thứ 3 là 0, chúng ta sẽ thêm các giá trị đối số thứ 4 vào đối số thứ nhất


Bạn nên bao gồm một số lời giải thích cho những người không tuân theo phép thuật ghép nối không loại bỏ.
mickmackusa

0

nếu bạn muốn hợp nhất mảng trống với giá trị mới hiện có. Bạn phải khởi tạo nó trước.

$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

Hy vọng sự giúp đỡ của nó.


0

vòng lặp foreach nhanh hơn mảng_merge để nối các giá trị vào một mảng hiện có, vì vậy hãy chọn vòng lặp thay thế nếu bạn muốn thêm một mảng vào cuối mảng khác.

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

Câu trả lời này không mang lại bất kỳ thông tin mới nào cho trang. So sánh hiệu suất đã được đăng năm trước.
mickmackusa

-4

Còn cái này thì sao:

$appended = $a + $b;

1
Nó sẽ so sánh các khóa, như tôi đã nói, và kết quả là như sau: Mảng ([0] => a [1] => b)
Danil K

1
Bạn có chắc chắn nó sẽ so sánh các phím? Nói tài liệu (mỏ nhấn mạnh): "Nếu các mảng đầu vào có cùng các khóa chuỗi, thì giá trị sau cho khóa đó sẽ ghi đè lên trước đó. Tuy nhiên, nếu các mảng chứa các khóa số, giá trị sau sẽ không ghi đè lên bản gốc giá trị, nhưng sẽ được nối thêm. ". Bạn có chắc là chìa khóa của bạn không thực sự '0' => 'a'... thay vì 0 => 'a'?
Piskvor rời khỏi tòa nhà vào

@Piskvor không có sự khác biệt giữa '0' và 0 cho các phím.
Gordon

Gordon nói đúng. Sự nhấn mạnh là các phím số (trái ngược với các phím số nguyên ).
netcoder

1
@Gordon: Ah, bạn nói đúng - đó là những gì tôi nhận được khi nghĩ về hai điều cùng một lúc. php.net/manual/en/lingu.operators.array.php là tài liệu choarray + array
Piskvor rời khỏi tòa nhà vào
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.