O PHP anexa uma matriz à outra (não array_push ou +)

278

Como anexar uma matriz a outra sem comparar suas chaves?

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

No final, deve ser: Array( [0]=>a [1]=>b [2]=>c [3]=>d ) Se eu usar algo como []ou array_push, causará um destes resultados:

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

Apenas deveria ser algo, fazendo isso, mas de uma maneira mais elegante:

foreach ( $b AS $var )
    $a[] = $var;
Danil K
fonte
16
array_merge ($a, $b)deve fazer exatamente o que você deseja, pelo menos com o PHP 5+.
tloach
1
(related) + Operator for Array in PHP
Gordon
6
nenhuma das saídas que você postou vem da array_merge();saída de array_merge();deve ser exatamente o que você precisa:print_r(array_merge($a,$b)); // outputs => Array ( [0] => a [1] => b [2] => c [3] => d )
acm
2
Eu discordo totalmente do termo "anexar". Anexar realmente significa que itens de uma matriz se tornam elementos de outra matriz (destino) que já pode ter alguns elementos, alterando, portanto, a matriz de destino. A mesclagem aloca uma nova matriz e os elementos COPIES de ambas as matrizes, enquanto que acréscimo na verdade significa reutilizar os elementos da matriz de destino sem alocação de memória extra.
tishma 23/07

Respostas:

424

array_merge é a maneira elegante:

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

Fazendo algo como:

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

Não funcionará, porque o +operador não os mescla. Se eles $ativerem as mesmas chaves $b, não fará nada.

codificador de rede
fonte
16
Apenas tome cuidado se suas chaves não são números, mas cadeias de caracteres. Do doc: se as matrizes de entrada tiverem as mesmas chaves de cadeia, o valor posterior dessa chave substituirá a anterior
Dusan Plavak
ou use o operador moderno de splat como resposta @bstoney stackoverflow.com/a/37065301/962634
basil
76

Outra maneira de fazer isso no PHP 5.6+ seria usar o ...token

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

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

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

Isso também funcionará com qualquer 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');

Um aviso, porém:

  • nas versões PHP anteriores à 7.3 isso causará um erro fatal se $bfor uma matriz vazia ou não for passível de passagem, por exemplo, não uma matriz
  • no PHP 7.3, um aviso será gerado se $bnão for possível atravessar
bstoney
fonte
Qual termo é usado para essa sintaxe? (Por exemplo, em JS, isso é chamado de operador de propagação). Ou você pode fornecer um link para os documentos?
basil
3
@ basil você encontrará ...comumente referido como o splat operatorem php.
precisa saber é o seguinte
A resposta mais útil ao procurar uma maneira simples de anexar uma matriz a si mesma sem substituir nenhum elemento anterior.
Daniel Böttner 15/07/19
1
array_pushaceita um argumento único desde o php 7.3, que evita erros com matrizes vazias.
vctls
na verdade, essa é a maneira mais elegante e eficiente. obrigado
Hassan Ali Salem
33

Por que não usar

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

Por que você não deseja usar esse método correto e interno?

Mark Baker
fonte
Onde o OP diz que ele "não quer usar" array_merge () ...?
KittenCodings
3
@KittenCodings - leia a "História Editar" da questão ... a pergunta original tinha direito PHP append one array to another (not array_merge or array_push)... posteriormente modificado para PHP append one array to another (not array_merge or +)antes de mudar para o título atual
Mark Baker
2
@MarkBaker Wow! Eu não sabia que SO tem um histórico de edições! Desculpe por isso, e obrigado, isso muda bastante e, de certa forma, impede que moderadores coloquem palavras na boca das pessoas, eu já senti que algumas perguntas foram desfiguradas e seus comentários invalidados pelo conteúdo removido / editado, embora eu imagino que a maioria das pessoas provavelmente não lê o histórico de edição, tenho certeza que Parreira a partir de agora
KittenCodings
21

É um post bastante antigo, mas quero adicionar algo sobre como anexar um array a outro:

E se

  • uma ou ambas as matrizes têm chaves associativas
  • as chaves de ambas as matrizes não importam

você pode usar funções de matriz como esta:

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

array_merge não mescla chaves numéricas, portanto acrescenta todos os valores de $ appendArray. Ao usar funções php nativas em vez de um loop foreach, deve ser mais rápido em matrizes com muitos elementos.

Adição 2019-12-13: Desde o PHP 7.4, existe a possibilidade de acrescentar ou acrescentar arrays da maneira Array Spread Operator:

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

Como antes, as chaves podem ser um problema com este novo recurso:

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

"Erro fatal: Erro não capturado: Não é possível descompactar a matriz com chaves de seqüência de caracteres"

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

matriz (4) {[1] => int (1) [4] => int (2) [5] => int (3) [6] => int (4)}

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

matriz (3) {[0] => int (1) [1] => int (4) [3] => int (3)}

SenseException
fonte
1
Isso também deve ter a vantagem de deixar as matrizes de entrada intocadas.
Jon Surrell 04/04
1
Sim, é mais seguro extrair os array_values ​​para que você não se mescle nas mesmas chaves.
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));
?>

Resultado:

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
)

Código Fonte de Referência

Hassan Amir Khan
fonte
12

Para grandes matrizes, é melhor concatenar sem array_merge, para evitar uma cópia de memória.

$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
fonte
Funciona como um encanto, para mim, essa abordagem foi 50x mais rápida.
luttkens
9

Seguindo as respostas de bstoney e Snark, fiz alguns testes nos vários métodos:

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

O que produz:

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

ORIGINAL: Acredito que, a partir do PHP 7, o método 3 é uma alternativa significativamente melhor devido à maneira como cada loop atua agora , que é fazer uma cópia da matriz que está sendo iterada.

Embora o método 3 não seja estritamente uma resposta aos critérios de 'not array_push' na pergunta, é uma linha e o desempenho mais alto em todos os aspectos, acho que a pergunta foi feita antes da sintaxe ... ser uma opção.

ATUALIZAÇÃO 25/03/2020: Atualizei o teste com defeito, pois as variáveis ​​não foram redefinidas. De maneira interessante (ou confusa), os resultados agora mostram que o teste 1 é o mais rápido, onde foi o mais lento, tendo passado de 0,008392 para 0,002717! Isso só pode ser devido às atualizações do PHP, pois isso não teria sido afetado pela falha de teste.

Então, a saga continua, vou começar a usar array_merge a partir de agora!

Jamie Robinson
fonte
2
Você não está redefinindo a matriz1 antes de cada teste, portanto, cada teste tem 50.000 itens a mais que o anterior.
Dakusan 22/02
Incrível, depois de tantos anos, você é a primeira pessoa a me ajudar nisso, obrigado. Vou fazer um novo teste em breve :)
Jamie Robinson
5

Desde o PHP 7.4 você pode usar o ... operador . Isso também é conhecido como operador splat em outros idiomas, incluindo Ruby.

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

Resultado

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

O operador Splat deve ter melhor desempenho que array_merge . Isso não é apenas porque o operador splat é uma estrutura de linguagem, enquanto array_merge é uma função, mas também porque a otimização do tempo de compilação pode ter desempenho para matrizes constantes.

Além disso, podemos usar a sintaxe do operador splat em qualquer lugar da matriz, pois elementos normais podem ser adicionados antes ou depois do operador splat.

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

Antes do PHP7, você pode usar:

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

array_splice()opera com referência à matriz (1º argumento) e coloca os valores da matriz (4º argumento) no lugar da lista de valores iniciados no 2º argumento e no número do 3º argumento. Quando definimos o 2º argumento como final da matriz de origem e o 3º como zero, acrescentamos o 4º valor do argumento ao 1º argumento

tutankhamun
fonte
Você deve incluir alguma explicação para aqueles que não seguem a mágica de emenda que não remove.
Mckmackusa
0

se você deseja mesclar matriz vazia com o novo valor existente. Você deve inicializá-lo primeiro.

$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

Espero que ajude.

drosanda
fonte
0

O loop foreach é mais rápido que o array_merge para anexar valores a um array existente; portanto, escolha o loop se desejar adicionar um array ao final de outro.

// 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
fonte
Esta resposta não traz nenhuma informação nova para a página. As comparações de desempenho foram publicadas anos antes.
Mckmackusa 21/01/19
-4

Que tal agora:

$appended = $a + $b;
Piskvor saiu do prédio
fonte
1
Ele comparará as chaves, como eu disse, e resultará no seguinte: Matriz ([0] => a [1] => b) #
Danil K
1
Tem certeza de que comparará as chaves? Diz a documentação (ênfase minha): "Se as matrizes de entrada tiverem as mesmas chaves de sequência, o valor posterior dessa chave substituirá a anterior. Se, no entanto, as matrizes contiverem teclas numéricas, o valor posterior não substituirá o original. valor, mas será anexado. " Tem certeza de que suas chaves não são realmente '0' => 'a'... em vez de 0 => 'a'?
Piskvor saiu do prédio
@Piskvor, não há diferença entre '0' e 0 para chaves.
Gordon
Gordon está certo. A ênfase está nas teclas numéricas (em oposição às teclas inteiras ).
Netcoder
1
@Gordon: Ah, você está certo - é isso que recebo por pensar em duas coisas ao mesmo tempo. php.net/manual/en/language.operators.array.php é uma documentação paraarray + array
Piskvor saiu do prédio