PHP aggiunge un array a un altro (non array_push o +)


278

Come aggiungere un array a un altro senza confrontare le loro chiavi?

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

Alla fine dovrebbe essere: Array( [0]=>a [1]=>b [2]=>c [3]=>d ) Se uso qualcosa di simile []o array_push, causerà uno di questi risultati:

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

Dovrebbe essere qualcosa, farlo, ma in un modo più elegante:

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

16
array_merge ($a, $b)dovrebbe fare esattamente quello che vuoi, almeno con PHP 5+.
contattare il


6
nessuno degli output che hai pubblicato proviene array_merge();dall'output di array_merge();dovrebbe essere esattamente ciò di cui hai bisogno:print_r(array_merge($a,$b)); // outputs => Array ( [0] => a [1] => b [2] => c [3] => d )
acm

2
Sono totalmente in disaccordo con il termine "append". Append significa che gli elementi di un array diventano elementi di un altro array (destinazione) che potrebbe già avere alcuni elementi, cambiando quindi l'array di destinazione. Unisci alloca un nuovo array e COPIA gli elementi di entrambi gli array, mentre append in realtà significa riutilizzare gli elementi dell'array di destinazione senza ulteriore allocazione di memoria.
tishma,

Risposte:


425

array_merge è il modo elegante:

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

Fare qualcosa del tipo:

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

Non funzionerà perché l' +operatore non li unisce. Se hanno $ale stesse chiavi di $b, non farà nulla.


16
Fai solo attenzione se le tue chiavi non sono numeri ma stringhe, Da doc: se gli array di input hanno le stesse chiavi di stringa, il valore successivo per quella chiave sovrascriverà quello precedente
Dusan Plavak

o utilizzare il moderno simbolo di operatore @bstoney risposta stackoverflow.com/a/37065301/962634
basilico

76

Un altro modo per farlo in PHP 5.6+ sarebbe usare il ...token

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

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

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

Questo funzionerà anche con qualsiasi 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');

Un avvertimento però:

  • nelle versioni PHP precedenti alla 7.3 ciò causerà un errore fatale se si $btratta di un array vuoto o non attraversabile, ad esempio non un array
  • in PHP 7.3 verrà emesso un avviso se $bnon è attraversabile

Quale termine viene utilizzato per tale sintassi? (Ad esempio in JS si chiama spread operator) O puoi fornire link a documenti?
basilico

3
@basil troverai ...comunemente indicato come splat operatorin php.
Mickmackusa,

La risposta più utile quando si cerca un modo semplice per aggiungere un array a se stesso senza sovrascrivere alcun elemento precedente.
Daniel Böttner,

1
array_pushaccetta un singolo argomento dal php 7.3, che impedisce errori con array vuoti.
vctls,

in realtà, questo è il modo più elegante ed efficiente. grazie
Hassan Ali Salem,

33

Perché non usare

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

Perché non vuoi usare questo, il metodo integrato corretto.


Dove dice OP che "non vuole usare" array_merge () ...?
KittenCodings

3
@KittenCodings - Leggi la "modifica cronologia" della domanda ... la domanda originale era intitolata PHP append one array to another (not array_merge or array_push)... successivamente modificata PHP append one array to another (not array_merge or +)prima di passare al titolo attuale
Mark Baker

2
@MarkBaker Wow! Non sapevo che SO avesse una cronologia delle modifiche! Mi dispiace, e grazie, questo cambia molto e in qualche modo impedisce ai moderatori di mettere le parole in bocca alle persone, in precedenza mi sentivo come se alcune domande fossero state cancellate e i loro commenti invalidati dal contenuto rimosso / modificato, anche se immagino che molte persone probabilmente non leggono la cronologia delle modifiche, sicuramente da ora in poi
KittenCodings

21

È un post piuttosto vecchio, ma voglio aggiungere qualcosa sull'aggiunta di un array a un altro:

Se

  • uno o entrambi gli array hanno chiavi associative
  • le chiavi di entrambi gli array non contano

puoi usare funzioni di array come questa:

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

array_merge non unisce le chiavi numeriche, quindi aggiunge tutti i valori di $ appendArray. Mentre si usano le funzioni php native invece di un ciclo foreach, dovrebbe essere più veloce su array con molti elementi.

Aggiunta 13-12-2019: da PHP 7.4, esiste la possibilità di aggiungere o anteporre array in modo Operatore diffusione array:

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

Come prima, le chiavi possono rappresentare un problema con questa nuova funzionalità:

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

"Errore irreversibile: errore non rilevato: impossibile decomprimere l'array con le chiavi di stringa"

    $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
Ciò dovrebbe anche avere il vantaggio di lasciare intatte le matrici di input.
Jon Surrell,

1
Sì, è più sicuro nel caso in cui estrarre array_values ​​in modo da non unire le stesse chiavi.
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));
?>

Produzione:

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
)

Codice sorgente di riferimento


12

Per array di grandi dimensioni, è meglio concatenare senza array_merge, per evitare una copia di memoria.

$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

Funziona come un incantesimo, per me questo approccio è stato 50 volte più veloce.
Lututt

9

In seguito alle risposte di bstoney e Snark ho fatto alcuni test sui vari metodi:

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

Che produce:

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

ORIGINALE: Credo che a partire da PHP 7, il metodo 3 sia un'alternativa significativamente migliore a causa del modo in cui agiscono i loop foreach , che consiste nel creare una copia dell'array su cui si sta eseguendo l'iterazione.

Mentre il metodo 3 non è strettamente una risposta ai criteri di "non array_push" nella domanda, è una riga e le prestazioni più elevate sotto tutti gli aspetti, penso che la domanda sia stata posta prima che la ... sintassi fosse un'opzione.

AGGIORNAMENTO 25/03/2020: Ho aggiornato il test che era difettoso poiché le variabili non sono state ripristinate. È interessante notare (o confusamente) che i risultati ora mostrano che il test 1 è il più veloce, dove è stato il più lento, passando da 0,008392 a 0,002717! Questo può dipendere solo dagli aggiornamenti di PHP, in quanto ciò non avrebbe risentito del difetto di verifica.

Quindi, continua la saga, inizierò ad usare array_merge da ora in poi!


2
Non stai ripristinando array1 prima di ogni test, quindi ogni test ha 50.000 elementi in più rispetto al precedente.
Dakusan,

Incredibile dopo tanti anni che sei la prima persona a prendermi in considerazione, grazie, farò un nuovo test a breve :)
Jamie Robinson,

5

Dal momento che PHP 7.4 è possibile utilizzare il ... dell'operatore . Questo è anche noto come operatore splat in altre lingue, incluso Ruby.

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

Produzione

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

L'operatore Splat dovrebbe avere prestazioni migliori di array_merge . Questo non solo perché l'operatore splat è una struttura linguistica mentre array_merge è una funzione, ma anche perché l'ottimizzazione del tempo di compilazione può essere performante per array costanti.

Inoltre, possiamo usare la sintassi dell'operatore splat ovunque nell'array, poiché è possibile aggiungere elementi normali prima o dopo l'operatore splat.

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

3

Prima di PHP7 puoi usare:

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

array_splice()opera con riferimento all'array (1 ° argomento) e inserisce i valori dell'array (4 ° argomento) al posto dell'elenco di valori iniziato dal 2 ° argomento e il numero del 3 ° argomento. Quando impostiamo il secondo argomento come fine dell'array di origine e il terzo come zero, aggiungiamo i valori del quarto argomento al primo argomento


Dovresti includere alcune spiegazioni a coloro che non seguono la magia di splicing che non rimuove.
Mickmackusa,

0

se si desidera unire un array vuoto con un nuovo valore esistente. È necessario inizializzarlo prima.

$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

Spero che sia di aiuto.


0

foreach loop è più veloce di array_merge per aggiungere valori a un array esistente, quindi scegli il loop invece se vuoi aggiungere un array alla fine di un altro.

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

Questa risposta non porta nuove informazioni alla pagina. I confronti delle prestazioni sono stati pubblicati anni prima.
Mickmackusa,

-4

Cosa ne pensi di questo:

$appended = $a + $b;

1
Confronterà le chiavi, come ho detto, e risulterà con quanto segue: Matrice ([0] => a [1] => b)
Danil K

1
Sei sicuro che confronterà le chiavi? Dice la documentazione (sottolineatura mia): "Se gli array di input hanno le stesse chiavi di stringa, il valore successivo per quella chiave sovrascriverà quello precedente. Se, tuttavia, gli array contengono chiavi numeriche, il valore successivo non sovrascriverà l'originale valore, ma verrà aggiunto. ". Sei sicuro che le tue chiavi non siano in realtà '0' => 'a'... invece di 0 => 'a'?
Piskvor lasciò l'edificio il

@Piskvor non c'è differenza tra '0' e 0 per i tasti.
Gordon,

Gordon ha ragione. L'enfasi è sui tasti numerici (al contrario dei tasti interi ).
netcoder

1
@Gordon: Ah, hai ragione - è quello che ottengo pensando a due cose contemporaneamente. php.net/manual/en/language.operators.array.php è la documentazione perarray + array
Piskvor ha lasciato l'edificio il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.