PHP dołącza jedną tablicę do drugiej (nie tablica_push lub +)

278

Jak dołączyć jedną tablicę do drugiej bez porównywania ich kluczy?

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

Na koniec powinno być: Array( [0]=>a [1]=>b [2]=>c [3]=>d ) jeśli użyję czegoś takiego jak []lub array_push, spowoduje to jeden z następujących wyników:

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

To powinno być coś, robi to, ale w bardziej elegancki sposób:

foreach ( $b AS $var )
    $a[] = $var;
Danil K.
źródło
16
array_merge ($a, $b)powinien robić dokładnie to, co chcesz, przynajmniej z PHP 5+.
tloach
1
(powiązane) + Operator for Array w PHP
Gordon
6
żadne z opublikowanych array_merge();wyników nie array_merge();powinno być dokładnie tym, czego potrzebujesz:print_r(array_merge($a,$b)); // outputs => Array ( [0] => a [1] => b [2] => c [3] => d )
acm
2
Całkowicie nie zgadzam się z terminem „append”. Dołącz naprawdę oznacza, że ​​elementy jednej tablicy stają się elementami innej (docelowej) tablicy, która może już zawierać pewne elementy, zmieniając w ten sposób tablicę docelową. Scal przydziela nową tablicę i KOPIE elementów obu tablic, a dołączenie oznacza ponowne użycie docelowych elementów tablicy bez dodatkowego przydziału pamięci.
tishma

Odpowiedzi:

424

array_merge jest elegancki sposób:

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

Robiąc coś takiego:

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

Nie będzie działać, ponieważ +operator tak naprawdę ich nie łączy. Jeśli mają $ate same klucze $b, nic nie zrobi.

netcoder
źródło
16
Bądź ostrożny, jeśli twoje klucze nie są cyframi, ale łańcuchami, Z dokumentu: Jeśli tablice wejściowe mają takie same klucze łańcuchowe, to późniejsza wartość tego klucza zastąpi poprzedni
Dusan Plavak
lub użyj nowoczesnego operatora splat jako @bstoney odpowiedz stackoverflow.com/a/37065301/962634
bazylia
76

Innym sposobem na zrobienie tego w PHP 5.6+ jest użycie ...tokena

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

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

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

Będzie to również działać z każdym 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');

Ostrzeżenie choć:

  • w wersjach PHP wcześniejszych niż 7.3 spowoduje to błąd krytyczny, jeśli $bjest pustą tablicą lub nie można jej przejść, np. nie jest tablicą
  • w PHP 7.3 pojawi się ostrzeżenie, jeśli $bnie jest możliwe przejście
bstoney
źródło
Którego terminu używa się na taką składnię? (Np. W JS nazywa się to operatorem rozprzestrzeniania). Czy możesz podać link do dokumentów?
bazylia
3
@basil będzie ...powszechnie określany jako splat operatorphp.
mickmackusa
Najbardziej użyteczna odpowiedź, gdy szukasz prostego sposobu na dołączenie tablicy do siebie bez przesłonięcia poprzednich elementów.
Daniel Böttner,
1
array_pushakceptuje pojedynczy argument od php 7.3, co zapobiega błędom przy pustych tablicach.
vctls
w rzeczywistości jest to najbardziej elegancki i wydajny sposób. dzięki
Hassan Ali Salem,
33

Dlaczego nie użyć?

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

Dlaczego nie chcesz użyć tej, poprawnej, wbudowanej metody.

Mark Baker
źródło
Gdzie OP mówi, że „nie chce używać” array_merge () ...?
KittenCodings
3
@KittenCodings - Przeczytaj „edytuj historię” pytania ... pierwotne pytanie było zatytułowane PHP append one array to another (not array_merge or array_push)… następnie zmodyfikowane PHP append one array to another (not array_merge or +)przed zmianą na obecny tytuł
Mark Baker
2
@MarkBaker Wow! Nie wiedziałem, że SO ma historię edycji! Przepraszam za to, a dzięki, to się bardzo zmienia i nieco uniemożliwia moderatorom wkładanie słów do ust ludzi, wcześniej czułem, że niektóre pytania zostały usunięte, a ich komentarze unieważnione przez treść usuniętą / zredagowaną, choć wyobrażam sobie, że większość ludzi prawdopodobnie nie czyta historia edycji, na pewno, jak do cholery, teraz
KittenCodings
21

To dość stary post, ale chcę dodać coś o dołączaniu jednej tablicy do drugiej:

Jeśli

  • jedna lub obie tablice mają klucze asocjacyjne
  • klucze obu tablic nie mają znaczenia

możesz użyć funkcji tablicowych takich jak to:

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

array_merge nie scala kluczy numerycznych, więc dołącza wszystkie wartości $ appendArray. Używając natywnych funkcji php zamiast pętli foreach, powinno być szybsze na tablicach z dużą ilością elementów.

Dodatek 13.12.2019: Od wersji PHP 7.4 istnieje możliwość dołączania lub dodawania tablic w sposób Array Spread Operator:

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

Tak jak poprzednio, klucze mogą być problemem z tą nową funkcją:

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

„Błąd krytyczny: nieprzechwycony błąd: nie można rozpakować tablicy za pomocą kluczy łańcuchowych”

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

SenseException
źródło
1
Powinno to również mieć tę zaletę, że tablice wejściowe pozostają nietknięte.
Jon Surrell
1
Tak, bezpieczniej jest na wszelki wypadek wyodrębnić wartości array_values, aby nie scalić się w te same klucze.
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));
?>

Wynik:

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
)

Referencyjny kod źródłowy

Hassan Amir Khan
źródło
12

W przypadku dużej tablicy lepiej jest połączyć konkatencję bez array_merge, aby uniknąć kopiowania pamięci.

$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
Snark
źródło
Działa jak urok, dla mnie to podejście było 50 razy szybsze.
luttkens
9

Po odpowiedziach od bstoney i Snarka wykonałem kilka testów różnych metod:

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

Który produkuje:

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

ORYGINAL: Wierzę, że od PHP 7 metoda 3 jest znacznie lepszą alternatywą ze względu na sposób działania pętli foreach , który polega na tworzeniu kopii iterowanej tablicy.

Podczas gdy metoda 3 nie jest ściśle odpowiedzią na kryteria „not array_push” w pytaniu, jest to jedna linia i najwyższa wydajność pod każdym względem, myślę, że pytanie zostało zadane, zanim ... składnia była opcją.

AKTUALIZACJA 25.03.2020: Zaktualizowałem test, który był wadliwy, ponieważ zmienne nie zostały zresetowane. Co ciekawe (lub myląco) wyniki pokazują teraz, że test 1 jest najszybszy, gdzie był najwolniejszy, od 0,008392 do 0,002717! Może to wynikać tylko z aktualizacji PHP, ponieważ nie miałby na to wpływu błąd testowy.

Tak więc saga trwa, odtąd zacznę używać array_merge!

Jamie Robinson
źródło
2
Nie resetujesz tablicy1 przed każdym testem, więc w każdym teście jest o 50 000 więcej pozycji niż w poprzednim.
Dakusan
Niesamowite po tylu latach, że jesteś pierwszą osobą, która mnie podniosła, dziękuję, wkrótce powtórzę test :)
Jamie Robinson
5

Od PHP 7.4 można użyć ... operatora . Jest to również znane jako operator ikony w innych językach, w tym Ruby.

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

Wynik

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

Operator Splat powinien mieć lepszą wydajność niż array_merge . Nie tylko dlatego, że operator splat jest strukturą językową, podczas gdy array_merge jest funkcją, ale także dlatego, że optymalizacja czasu kompilacji może być wydajna dla stałych tablic.

Ponadto możemy używać składni operatora splat wszędzie w tablicy, ponieważ normalne elementy można dodawać przed lub po operatorze splat.

$arr1 = [1, 2, 3];
$arr2 = [4, 5, 6];
$arr3 = [...$arr1, ...$arr2];
$arr4 = [...$arr1, ...$arr3, 7, 8, 9];
dtar
źródło
3

Przed PHP7 możesz użyć:

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

array_splice()działa w odniesieniu do tablicy (1. argument) i umieszcza wartości tablicy (4. argument) w miejsce listy wartości rozpoczynanych od 2. argumentu i liczby 3. argumentu. Kiedy ustawiamy drugi argument jako koniec tablicy źródłowej, a trzeci jako zero, dołączamy 4. wartość argumentu do 1. argumentu

tutanchamon
źródło
Powinieneś dołączyć wyjaśnienie dla tych, którzy nie postępują zgodnie z nieusuwalną magią splicingu.
mickmackusa
0

jeśli chcesz scalić pustą tablicę z istniejącą nową wartością. Musisz go najpierw zainicjować.

$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

Mam nadzieję, że to pomoże.

drosanda
źródło
0

pętla foreach jest szybsza niż array_merge, aby dołączyć wartości do istniejącej tablicy, więc wybierz pętlę zamiast tego, jeśli chcesz dodać tablicę na końcu innej.

// 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
E_D
źródło
Ta odpowiedź nie przynosi żadnych nowych informacji na stronie. Porównanie wyników opublikowano wiele lat wcześniej.
mickmackusa
-4

Co powiesz na to:

$appended = $a + $b;
Piskvor opuścił budynek
źródło
1
Porówna klucze, jak powiedziałem, i otrzyma następujące wyniki: Array ([0] => a [1] => b)
Danil K
1
Czy jesteś pewien, że porówna klucze? Mówi dokumentacja (moje wyróżnienie): „Jeśli tablice wejściowe mają te same klucze łańcuchowe, to późniejsza wartość tego klucza zastąpi poprzednią. Jeśli jednak tablice zawierają klucze numeryczne, późniejsza wartość nie zastąpi oryginalnej wartość, ale zostanie dołączona. ”. Czy na pewno twoje klucze nie są '0' => 'a'... zamiast 0 => 'a'?
Piskvor opuścił budynek
@Piskvor nie ma różnicy między „0” a 0 dla kluczy.
Gordon
Gordon ma rację. Nacisk kładziony jest na klawisze numeryczne (w przeciwieństwie do klawiszy całkowitych ).
netcoder
1
@Gordon: Ach, masz rację - tak rozumiem dwie rzeczy naraz. php.net/manual/en/language.operators.array.php jest dokumentacją dlaarray + array
Piskvor opuścił budynek