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;

16
array_merge ($a, $b)devrait faire exactement ce que vous voulez, au moins avec PHP 5+.
tloach


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.


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

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.


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


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


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

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!


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

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


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.


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

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;

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.