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+.
голосувати


6
жоден із результатів, які ви опублікували, не надходить із array_merge();результатів, не array_merge();повинен бути точним, що вам потрібно:print_r(array_merge($a,$b)); // outputs => Array ( [0] => a [1] => b [2] => c [3] => d )
acm

2
Я повністю не згоден з терміном "додати". Додавання дійсно означає, що елементи одного масиву стають елементами іншого (призначення) масиву, який може вже мати деякі елементи, тому змінюючи масив призначення. Злиття виділяє новий масив та COPIES елементи обох масивів, тоді як додавання фактично означає повторне використання елементів масиву призначення без додаткового розподілу пам'яті.
тишма

Відповіді:


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: Якщо вхідні масиви мають однакові рядкові клавіші, то пізніше значення для цього ключа буде замінено попереднім
Душан Плавак

або використовувати сучасний пейнтбольний оператор як @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');

Однак попередження :

  • у версіях PHP до 7.3 це призведе до фатальної помилки, якщо $bце порожній масив чи не проходить, наприклад, не масив
  • у PHP 7.3 буде попереджено попередження, якщо $bвоно не проходить

Який термін використовується для такого синтаксису? (Наприклад, в JS це називається оператором розповсюдження) Або ви можете надати посилання на документи?
базилік

3
@basil ви знайдете, ...як називають splat operatorу php.
mickmackusa

Найкорисніша відповідь при пошуку простого способу додавання масиву до себе, не змінюючи жодних попередніх елементів.
Даніель Беттнер

1
array_pushприймає єдиний аргумент, оскільки php 7.3, що запобігає помилкам з порожніми масивами.
vctls

насправді це найелегантніший та найефективніший спосіб. спасибі
Хассан Алі Салем

33

Чому б не використовувати

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

Чому ви не хочете використовувати цей, правильний, вбудований метод.


Де ОП каже, що "не хоче використовувати" 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 +)зміни його поточної назви
Марк Бейкер

2
@MarkBaker Нічого собі! Я не знав, SO має історію редагування! Вибачте з цього приводу, і дякую, що це сильно змінюється і дещо заважає модераторам вводити слова в рот людей, я раніше відчував, що деякі запитання відхиляються, а їх коментарі недійсні за зміст видаляються / редагуються, хоча я думаю, що більшість людей, напевно, не читають історія редагування, я впевнений, що чорт відтепер буде
KittenCodings

21

Це досить стара публікація, але я хочу додати щось про додавання одного масиву до іншого:

Якщо

  • один або обидва масиви мають асоціативні ключі
  • ключі обох масивів не мають значення

Ви можете використовувати такі функції масиву:

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

"Fatal error: Uncaught Error: Неможливо розпакувати масив за допомогою рядкових клавіш"

    $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
Це також повинно мати перевагу, залишаючи вхідні масиви недоторканими.
Джон Суррелл

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

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" у питанні, це один рядок і найбільш висока продуктивність у всіх відношеннях, я думаю, що питання було задано до того, як ... синтаксис був варіантом.

ОНОВЛЕННЯ 25/03/2020: Я оновив тест, який був помилковим, оскільки змінні не були скинуті. Цікаво (або заплутано) результати тепер показують, що тест 1 є найшвидшим, де він був найповільнішим, пройшовши з 0,008392 до 0,002717! Це може бути обмежено лише оновленнями PHP, оскільки це не вплинуло б на помилку тестування.

Отже, сага продовжується, я зараз почну використовувати array_merge!


2
Ви не скидаєте array1 перед кожним тестом, тому кожен тест має на 50 000 більше елементів, ніж попередній.
Дакусан

Дивно після стількох років, що ви перша людина, яка взяла мене за це, дякую, незабаром проведу повторний тест :)
Джеймі Робінсон,

5

Починаючи з PHP 7.4 ви можете використовувати ... оператор . Це також відоме як оператор splat іншими мовами, включаючи 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"
}

Оператор 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()працює з посиланням на масив (1-й аргумент) і ставить значення масиву (4-й аргумент) замість списку значень, що починається з 2-го аргументу та числа 3-го аргументу. Коли ми встановлюємо 2-й аргумент як кінець вихідного масиву, а 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 швидше, ніж 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

1
Ви впевнені, що він порівнюватиме ключі? Каже в документації (моє наголос): "Якщо вхідні масиви мають однакові рядкові клавіші, то пізніше значення для цього ключа буде перезаписано попереднє. Якщо, однак, масиви містять числові ключі, пізніше значення не замінить вихідне значення, але буде додано. " Ви впевнені, що ваші ключі насправді не є '0' => 'a'… замість 0 => 'a'?
Пісквор вийшов з будівлі

@Piskvor немає різниці між "0" і 0 для клавіш.
Гордон

Гордон правий. Акцент робиться на числових клавішах (на відміну від цілих клавіш ).
netcoder

1
@Gordon: Ах, ти маєш рацію - ось що я розумію відразу про дві речі. php.net/manual/en/language.operators.array.php - це документація дляarray + array
Piskvor вийшов з будинку
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.