PHP ajoute un tableau à un autre (pas array_push ou +)

278

Comment ajouter un tableau à un autre sans comparer leurs clés?

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

À la fin, cela devrait être: Array( [0]=>a [1]=>b [2]=>c [3]=>d ) si j'utilise quelque chose comme []ou array_push, cela entraînera l'un des résultats suivants:

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

Cela devrait être quelque chose, faire cela, mais d'une manière plus élégante:

foreach ( $b AS $var )
    $a[] = $var;
Danil K
la source
16
array_merge ($a, $b)devrait faire exactement ce que vous voulez, au moins avec PHP 5+.
tloach
1
(en relation) + Opérateur pour Array en PHP
Gordon
6
aucune des sorties que vous avez affichée proviennent de array_merge();la sortie array_merge();devrait être exaclty ce que vous avez besoin:print_r(array_merge($a,$b)); // outputs => Array ( [0] => a [1] => b [2] => c [3] => d )
acm
2
Je suis totalement en désaccord avec le terme "ajouter". Ajouter signifie vraiment que les éléments d'un tableau deviennent des éléments d'un autre tableau (de destination) qui pourrait déjà avoir certains éléments, modifiant ainsi le tableau de destination. La fusion alloue un nouveau tableau et des éléments COPIES des deux tableaux, tandis que l'ajout signifie en fait la réutilisation des éléments du tableau de destination sans allocation de mémoire supplémentaire.
tishma

Réponses:

425

array_merge est la manière élégante:

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

Faire quelque chose comme:

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

Ne fonctionnera pas, car l' +opérateur ne les fusionne pas réellement. S'ils ont $ales mêmes clés $b, cela ne fera rien.

netcoder
la source
16
Faites juste attention si vos clés ne sont pas des nombres mais des chaînes, Du doc: Si les tableaux d'entrée ont les mêmes clés de chaîne, alors la valeur ultérieure de cette clé remplacera la précédente
Dusan Plavak
ou utilisez un opérateur de splat moderne comme @bstoney answer stackoverflow.com/a/37065301/962634
basil
76

Une autre façon de faire cela en PHP 5.6+ serait d'utiliser le ...jeton

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

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

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

Cela fonctionnera également avec tout 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 avertissement cependant:

  • dans les versions PHP antérieures à 7.3, cela entraînera une erreur fatale s'il $bs'agit d'un tableau vide ou non traversable, par exemple pas un tableau
  • en PHP 7.3 un avertissement sera émis s'il $bn'est pas traversable
bstoney
la source
Quel terme est utilisé pour une telle syntaxe? (Par exemple, dans JS, il est appelé opérateur de propagation) Ou pouvez-vous fournir un lien vers des documents?
basilic
3
@basil, vous trouverez ...communément appelé le splat operatorphp.
mickmackusa
La réponse la plus utile lorsque vous recherchez un moyen simple d'ajouter un tableau à lui-même sans remplacer les éléments précédents.
Daniel Böttner
1
array_pushaccepte un seul argument depuis php 7.3, ce qui évite les erreurs avec des tableaux vides.
vctls
en fait, c'est le moyen le plus élégant et le plus efficace. merci
Hassan Ali Salem
33

Pourquoi ne pas utiliser

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

Pourquoi ne voulez-vous pas utiliser cela, la bonne méthode intégrée.

Mark Baker
la source
Où OP dit-il qu'il "ne veut pas utiliser" array_merge () ...?
KittenCodings
3
@KittenCodings - Lisez l '"historique des modifications" de la question ... la question d'origine était intitulée PHP append one array to another (not array_merge or array_push)... modifiée par la suite PHP append one array to another (not array_merge or +)avant d'être remplacée par son titre actuel
Mark Baker
2
@MarkBaker Wow! Je ne savais pas que SO avait un historique d'édition! Désolé, et cela change beaucoup et empêche quelque peu les modérateurs de mettre des mots dans la bouche des gens.J'avais auparavant l'impression que certaines questions avaient été effacées et leurs commentaires invalidés par le contenu supprimé / modifié, bien que j'imagine que la plupart des gens ne lisent probablement pas l'historique des modifications, je suis sûr que je le ferai désormais
KittenCodings
21

C'est un article assez ancien, mais je veux ajouter quelque chose sur l'ajout d'un tableau à un autre:

Si

  • un ou les deux tableaux ont des clés associatives
  • les clés des deux tableaux n'ont pas d'importance

vous pouvez utiliser des fonctions de tableau comme ceci:

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

array_merge ne fusionne pas les clés numériques, il ajoute donc toutes les valeurs de $ appendArray. Tout en utilisant des fonctions php natives au lieu d'une boucle foreach, cela devrait être plus rapide sur les tableaux avec beaucoup d'éléments.

Ajout 2019-12-13: Depuis PHP 7.4, il y a la possibilité d'ajouter ou de pré-ajouter des tableaux de la manière Array Spread Operator:

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

Comme précédemment, les clés peuvent être un problème avec cette nouvelle fonctionnalité:

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

"Erreur fatale: erreur non interceptée: impossible de décompresser le tableau avec les clés de chaîne"

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

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

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

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

SenseException
la source
1
Cela devrait également avoir l'avantage de laisser les tableaux d'entrée intacts.
Jon Surrell
1
Oui, il est plus sûr au cas où d'extraire les valeurs de tableau afin de ne pas fusionner dans les mêmes clés.
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));
?>

Production:

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
)

Code source de référence

Hassan Amir Khan
la source
12

Pour un grand tableau, il est préférable de concaténer sans array_merge, pour éviter une copie de la mémoire.

$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
la source
Fonctionne comme un charme, pour moi, cette approche était 50 fois plus rapide.
luttkens
9

Suite aux réponses de bstoney et Snark, j'ai fait quelques tests sur les différentes méthodes:

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

Ce qui produit:

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

ORIGINAL: Je pense qu'à partir de PHP 7, la méthode 3 est une alternative bien meilleure en raison de la façon dont les boucles foreach agissent maintenant , qui consiste à faire une copie du tableau en cours d'itération.

Bien que la méthode 3 ne soit pas strictement une réponse aux critères de 'not array_push' dans la question, c'est une ligne et la plus haute performance à tous égards, je pense que la question a été posée avant que la syntaxe ... soit une option.

MISE À JOUR 25/03/2020: J'ai mis à jour le test qui était défectueux car les variables n'étaient pas réinitialisées. Fait intéressant (ou confus), les résultats montrent maintenant que le test 1 est le plus rapide, où il était le plus lent, étant passé de 0,008392 à 0,002717! Cela ne peut être dû qu'aux mises à jour PHP, car cela n'aurait pas été affecté par la faille de test.

Donc, la saga continue, je vais commencer à utiliser array_merge à partir de maintenant!

Jamie Robinson
la source
2
Vous ne réinitialisez pas array1 avant chaque test, donc chaque test contient 50 000 éléments de plus que le précédent.
Dakusan
Incroyable après tant d'années, vous êtes la première personne à venir me chercher à ce sujet, merci, je ferai un nouveau test sous peu :)
Jamie Robinson
5

Depuis PHP 7.4 , vous pouvez utiliser le ... opérateur . Ceci est également connu comme l' opérateur splat dans d'autres langues, y compris Ruby.

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

Production

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

L'opérateur Splat devrait avoir de meilleures performances que array_merge . Ce n'est pas seulement parce que l'opérateur splat est une structure de langage alors que array_merge est une fonction, mais aussi parce que l'optimisation du temps de compilation peut être performante pour des tableaux constants.

De plus, nous pouvons utiliser la syntaxe de l'opérateur splat partout dans le tableau, car des éléments normaux peuvent être ajoutés avant ou après l'opérateur splat.

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

Avant PHP7, vous pouvez utiliser:

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

array_splice()fonctionne en référence au tableau (1er argument) et place les valeurs du tableau (4e argument) à la place de la liste des valeurs démarrées à partir du 2e argument et du nombre du 3e argument. Lorsque nous définissons le 2e argument comme fin du tableau source et le 3e comme zéro, nous ajoutons les valeurs du 4e argument au 1er argument

Toutankhamon
la source
Vous devriez inclure une explication à ceux qui ne suivent pas la magie d'épissage non supprimante.
mickmackusa
0

si vous souhaitez fusionner un tableau vide avec une nouvelle valeur existante. Vous devez d'abord l'initialiser.

$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

J'espère que son aide.

drosanda
la source
0

la boucle foreach est plus rapide que array_merge pour ajouter des valeurs à un tableau existant, choisissez donc la boucle à la place si vous souhaitez ajouter un tableau à la fin d'un autre.

// 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
la source
Cette réponse n'apporte aucune nouvelle information à la page. Des comparaisons de performances ont été publiées des années auparavant.
mickmackusa
-4

Que dis-tu de ça:

$appended = $a + $b;
Piskvor a quitté le bâtiment
la source
1
Il comparera les clés, comme je l'ai dit, et donnera les résultats suivants: Array ([0] => a [1] => b)
Danil K
1
Voulez-vous vraiment comparer les clés? Dit la documentation (soulignement le mien): "Si les tableaux en entrée ont les mêmes clés de chaîne, alors la valeur ultérieure de cette clé remplacera la précédente. Si, cependant, les tableaux contiennent des clés numériques, la valeur ultérieure ne remplacera pas l'original , mais sera ajouté. ". Êtes-vous sûr que vos clés ne sont pas réellement '0' => 'a'... au lieu de 0 => 'a'?
Piskvor a quitté le bâtiment
@Piskvor il n'y a pas de différence entre '0' et 0 pour les clés.
Gordon
Gordon a raison. L'accent est mis sur les touches numériques (par opposition aux clés entières ).
netcoder
1
@Gordon: Ah, vous avez raison - c'est ce que j'obtiens en pensant à deux choses à la fois. php.net/manual/en/language.operators.array.php est une documentation pourarray + array
Piskvor a quitté le bâtiment