Comment insérer un élément dans un tableau à un index spécifique (JavaScript)?


2932

Je recherche une méthode d'insertion de tableau JavaScript, dans le style de:

arr.insert(index, item)

De préférence dans jQuery, mais toute implémentation JavaScript fera l'affaire à ce stade.


96
Notez que JQuery est une bibliothèque de manipulation de DOM et d'événement, pas un langage qui lui est propre. Cela n'a rien à voir avec la manipulation de tableaux.
Domino

25
api.jquery.com/jQuery.inArray n'a rien à voir avec le DOM ou les événements. jQuery a évolué en une boîte à outils mixte pour le développement JS de navigateur, ce qui conduit les gens à s'attendre à ce qu'il ait une méthode pour tout.
Tim

4
@Tim, mais ce n'est toujours pas une langue à part (il y a encore des questions comme "comment additionner deux nombres dans jQuery" ici sur SO)
Victor

3
@Victor Non, et ne le sera jamais. jQuery était utile et pertinent, mais il a fait son temps.
Tim

1
Voir aussi ceci , pour une surprise tordue (:
noobie

Réponses:


4757

Ce que vous voulez, c'est la splicefonction sur l'objet tableau natif.

arr.splice(index, 0, item);s'insérera itemdans arrl'index spécifié (en supprimant d' 0abord les éléments, c'est-à-dire qu'il s'agit simplement d'un insert).

Dans cet exemple, nous allons créer un tableau et y ajouter un élément dans l'index 2:

var arr = [];
arr[0] = "Jani";
arr[1] = "Hege";
arr[2] = "Stale";
arr[3] = "Kai Jim";
arr[4] = "Borge";

console.log(arr.join());
arr.splice(2, 0, "Lene");
console.log(arr.join());


168
Merci, je pensais que je me sentirais stupide de demander mais maintenant que je connais la réponse, je ne sais pas! Pourquoi diable ont-ils décidé de l'appeler épissure alors qu'un terme plus consultable était couramment utilisé pour la même fonction?!
tags2k

83
@ tags2k: parce que la fonction fait plus qu'insérer des éléments et que son nom a déjà été établi en perl?
Christoph


55
Splice peut insérer, mais tout aussi souvent ne fonctionne pas . Par exemple: arr.splice(2,3)supprimera 3 éléments à partir de l'index 2. Sans passer le 3e .... Nième paramètres rien n'est inséré. Donc, le nom insert()ne lui rend pas justice non plus.
EBarr

14
Je pense que le terme «épissure» a du sens. Splice signifie rejoindre ou se connecter, aussi changer. Vous avez un tableau établi que vous "modifiez" maintenant, ce qui impliquerait l'ajout ou la suppression d'éléments. Vous spécifiez où commencer dans le tableau, puis le nombre d'anciens éléments à supprimer (le cas échéant) et enfin, éventuellement une liste de nouveaux éléments à ajouter. L'épissure est également un excellent terme de science-fiction, bien sûr.
Jakub Keller

285

Vous pouvez implémenter la Array.insertméthode en procédant comme suit:

Array.prototype.insert = function ( index, item ) {
    this.splice( index, 0, item );
};

Ensuite, vous pouvez l'utiliser comme:

var arr = [ 'A', 'B', 'D', 'E' ];
arr.insert(2, 'C');

// => arr == [ 'A', 'B', 'C', 'D', 'E' ]

9
Pour insérer plusieurs éléments, vous pouvez utiliserArray.prototype.insert = function (index, items) { this.splice.apply(this, [index, 0].concat(items)); }
Ryan Smith

7
Le problème avec l'ajout de trucs au tableau est que la fonction apparaîtra comme un élément lorsque vous le faites pour (i in arr) {...}
rep_movsd

7
Mais gardez à l'esprit qu'il n'est pas recommandé d'étendre les types natifs car cela pourrait interférer avec d'autres codes ou fonctionnalités futures.
marsze

17
Ne modifiez pas les objets que vous ne possédez pas
Luis Cabrera Benito

4
Ne modifiez pas les prototypes
satya164

141

Autre que l'épissure, vous pouvez utiliser cette approche qui ne mute pas le tableau d'origine, mais crée un nouveau tableau avec l'élément ajouté. Vous devriez généralement éviter la mutation chaque fois que possible. J'utilise l'opérateur de propagation ES6 ici.

const items = [1, 2, 3, 4, 5]

const insert = (arr, index, newItem) => [
  // part of the array before the specified index
  ...arr.slice(0, index),
  // inserted item
  newItem,
  // part of the array after the specified index
  ...arr.slice(index)
]

const result = insert(items, 1, 10)

console.log(result)
// [1, 10, 2, 3, 4, 5]

Cela peut être utilisé pour ajouter plus d'un élément en ajustant un peu la fonction pour utiliser l'opérateur de repos pour les nouveaux éléments, et le répartir également dans le résultat renvoyé

const items = [1, 2, 3, 4, 5]

const insert = (arr, index, ...newItems) => [
  // part of the array before the specified index
  ...arr.slice(0, index),
  // inserted items
  ...newItems,
  // part of the array after the specified index
  ...arr.slice(index)
]

const result = insert(items, 1, 10, 20)

console.log(result)
// [1, 10, 20, 2, 3, 4, 5]


1
Est-ce un bon moyen sûr de le faire? Je demande parce que cela semble si élégant et concis, mais aucune autre réponse ne touche à cela. La plupart d'entre eux modifient l'objet prototype!
Harsh Kanchina

5
@HarshKanchina C'est probablement parce que la plupart des réponses sont pré ES6, mais cette approche est très courante maintenant d'après mon expérience
gafi

77

insertMéthodes de tableau personnalisées

1. Avec plusieurs arguments et un support de chaînage

/* Syntax:
   array.insert(index, value1, value2, ..., valueN) */

Array.prototype.insert = function(index) {
    this.splice.apply(this, [index, 0].concat(
        Array.prototype.slice.call(arguments, 1)));
    return this;
};

Il peut insérer plusieurs éléments (comme le splicefait le natif ) et prend en charge le chaînage:

["a", "b", "c", "d"].insert(2, "X", "Y", "Z").slice(1, 6);
// ["b", "X", "Y", "Z", "c"]

2. Avec des arguments de type tableau fusionnant et prenant en charge le chaînage

/* Syntax:
   array.insert(index, value1, value2, ..., valueN) */

Array.prototype.insert = function(index) {
    index = Math.min(index, this.length);
    arguments.length > 1
        && this.splice.apply(this, [index, 0].concat([].pop.call(arguments)))
        && this.insert.apply(this, arguments);
    return this;
};

Il peut fusionner des tableaux à partir des arguments avec le tableau donné et prend également en charge le chaînage:

["a", "b", "c", "d"].insert(2, "V", ["W", "X", "Y"], "Z").join("-");
// "a-b-V-W-X-Y-Z-c-d"

DÉMO: http://jsfiddle.net/UPphH/


Existe-t-il un moyen compact pour que cette version fusionne également un tableau lorsqu'elle en trouve un dans les arguments?
Nolo

Je ne comprends pas le premier résultat ["b", "X", "Y", "Z", "c"]. Pourquoi n'est pas "d"inclus? Il me semble que si vous mettez 6 comme deuxième paramètre de slice()et qu'il y a 6 éléments dans le tableau à partir de l'index spécifié, alors vous devriez obtenir les 6 éléments dans la valeur de retour. (Le document dit howManypour ce paramètre.) Developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Alexis Wilke

En fait, si j'utilise un indice de 3 ou plus, je n'obtiens rien dans la sortie (cas 1., FireFox) ["a", "b", "c", "d"].insert(2, "X", "Y", "Z").slice(3, 3);=>[ ]
Alexis Wilke

@AlexisWilke Dans le premier exemple, j'ai utilisé la sliceméthode et non splice, à laquelle vous faites référence dans le commentaire. Le deuxième paramètre de slice(nommé end) est l' index de base zéro auquel terminer l'extraction. sliceextrait jusqu'à mais non comprisend . D'où après insertvous avez ["a", "b", "X", "Y", "Z", "c", "d"], d'où sliceextrait des éléments avec des indices de 1jusqu'à 6, c'est- à -dire de "b"à "d"mais n'incluant pas "d". Est-ce que ça fait du sens?
VisioN

41

Si vous souhaitez insérer plusieurs éléments dans un tableau à la fois, consultez cette réponse Stack Overflow: une meilleure façon de raccorder un tableau en un tableau en javascript

Voici également quelques fonctions pour illustrer les deux exemples:

function insertAt(array, index) {
    var arrayToInsert = Array.prototype.splice.apply(arguments, [2]);
    return insertArrayAt(array, index, arrayToInsert);
}

function insertArrayAt(array, index, arrayToInsert) {
    Array.prototype.splice.apply(array, [index, 0].concat(arrayToInsert));
    return array;
}

Enfin, voici un jsFiddle que vous pouvez voir par vous-même: http://jsfiddle.net/luisperezphd/Wc8aS/

Et voici comment vous utilisez les fonctions:

// if you want to insert specific values whether constants or variables:
insertAt(arr, 1, "x", "y", "z");

// OR if you have an array:
var arrToInsert = ["x", "y", "z"];
insertArrayAt(arr, 1, arrToInsert);

1
InsertAt () ne ferait-il pas mieux d'appeler insertArrayAt () une fois qu'il a créé un tableau à élément uniqueToInsert? Cela évite la répétition d'un code identique.
Matt Sach

1
ceci est un excellent exemple de l'utilisation de «appliquer»
CRice

J'ai ajouté un paramètre removeCount à cette méthode pour tirer parti de la capacité de splice à supprimer également des éléments à cet index: Array.prototype.splice.apply (array, [index, removeCount || 0] .concat (arrayToInsert));
CRice

23

Pour une programmation fonctionnelle et un enchaînement appropriés, une invention de Array.prototype.insert()est essentielle. En fait, l'épissage aurait pu être parfait s'il avait renvoyé le tableau muté au lieu d'un tableau vide totalement dénué de sens. Alors voilà

Array.prototype.insert = function(i,...rest){
  this.splice(i,0,...rest)
  return this
}

var a = [3,4,8,9];
document.write("<pre>" + JSON.stringify(a.insert(2,5,6,7)) + "</pre>");

Eh bien, ce qui précède avec Array.prototype.splice()celui mute le tableau d'origine et certains pourraient se plaindre comme "vous ne devriez pas modifier ce qui ne vous appartient pas" et cela pourrait aussi être correct. Donc, pour le bien-être public, je voudrais en donner un autre Array.prototype.insert()qui ne mute pas le tableau d'origine. Ça y va;

Array.prototype.insert = function(i,...rest){
  return this.slice(0,i).concat(rest,this.slice(i));
}

var a = [3,4,8,9],
    b = a.insert(2,5,6,7);
console.log(JSON.stringify(a));
console.log(JSON.stringify(b));


2
"un tableau vide totalement dénué de sens" - il ne renvoie un tableau vide que lorsque le deuxième paramètre est 0. S'il est supérieur à 0, il renvoie les éléments supprimés du tableau. Étant donné que vous ajoutez à un prototype et splicemute le tableau d'origine, je ne pense pas qu'une "programmation fonctionnelle appropriée" appartienne à quelque part à proximité de splice.
chrisbajorin

Nous parlons d'insérer ici et le deuxième paramètre de Array.prototype.splice () doit être zéro. Et ce qu'il retourne n'a pas d'autre signification que "je n'ai rien supprimé" et puisque nous l'utilisons pour insérer un élément, nous avons déjà cette information. Si vous ne voulez pas muter le tableau d'origine, vous pouvez faire de même avec deux opérations Array.prototype.slice () et une opération Array.prototype.concat (). C'est à vous.
Redu

1
Votre deuxième implémentation est la plus propre de toute cette page et vous n'avez aucun vote. Prenez le mien et continuez votre bon travail. (vous devriez juste éviter de muter le prototype mais vous le savez déjà)
NiKo

1
Je pense qu'il convient de mentionner que le paramètre de repos est le nouvel ECMA 6th ( developer.mozilla.org/en/docs/Web/JavaScript/Reference/… )
Geza Turi

18

Je recommande d'utiliser du JavaScript pur dans ce cas, il n'y a pas non plus de méthode d'insertion en JavaScript, mais nous avons une méthode qui est une méthode Array intégrée qui fait le travail pour vous, elle s'appelle splice ...

Voyons ce qui est splice () ...

La méthode splice () modifie le contenu d'un tableau en supprimant les éléments existants et / ou en ajoutant de nouveaux éléments.

OK, imaginez que nous avons ce tableau ci-dessous:

const arr = [1, 2, 3, 4, 5];

Nous pouvons supprimer 3comme ceci:

arr.splice(arr.indexOf(3), 1);

Il retournera 3, mais si nous vérifions l'arr maintenant, nous avons:

[1, 2, 4, 5]

Jusqu'à présent, tout va bien, mais comment pouvons-nous ajouter un nouvel élément au tableau en utilisant une épissure? Remettons 3 à l'arr ...

arr.splice(2, 0, 3);

Voyons voir ce que nous avons fait ...

Nous utilisons à nouveau l' épissure , mais cette fois pour le deuxième argument, nous passons 0 , cela signifie que nous ne voulons supprimer aucun élément, mais en même temps, nous ajoutons un troisième argument qui est 3 qui sera ajouté au deuxième index ...

Vous devez savoir que nous pouvons supprimer et ajouter en même temps, par exemple maintenant nous pouvons faire:

arr.splice(2, 2, 3);

Ce qui supprimera 2 éléments à l'index 2, puis en ajoutera 3 à l'index 2 et le résultat sera:

[1, 2, 3, 5];

Cela montre comment fonctionne chaque élément de l'épissure:

array.splice (start, deleteCount, item1, item2, item3 ...)


13

Ajouter un élément unique à un index spécifique

//Append at specific position(here at index 1)
arrName.splice(1, 0,'newName1');
//1: index number, 0: number of element to remove, newName1: new element


//Append at specific position (here at index 3)
arrName[3] = 'newName1';

Ajouter plusieurs éléments à un index spécifique

//Append from index number 1
arrName.splice(1, 0,'newElemenet1', 'newElemenet2', 'newElemenet3');
//1: index number from where append start, 
//0: number of element to remove, 
//newElemenet1,2,3: new elements

8
Il convient de noter que arrName [3] ne s'ajoute pas, il remplace.
sfratini

Il ajoute l'élément au tableau existant sans sur-ride, Ex: let arrName = ['xxx', 'yyy', 'zzz']; arrName.splice (1, 0, 'aaa', 'bbb', 'ccc'); après avoir imprimé l'arrName
Srikrushna

Si arrName a plus de 3 éléments, vous remplacez le 3ème, pas en ajoutant. Ou est-ce que je regarde cela dans le mauvais sens?
sfratini

Si nous insérons un élément au milieu, il décale l'élément suivant sans passer outre. Veuillez préciser votre problème, ce dont vous avez besoin. Prenez un tableau (exemple) et ce dont vous avez besoin sur la sortie. plz comment me
Srikrushna

1
@Srikrushna arrName[3] = 'newName1';s'ajoutera si le tableau n'a que 3 éléments. S'il y a un élément dans l'index 3, il sera remplacé. Si vous souhaitez ajouter à la fin, il est préférable d'utiliserarrName.push('newName1');
awe

6

Une autre solution possible, avec l'utilisation de Array#reduce.

var arr = ["apple", "orange", "raspberry"],
    arr2 = [1, 2, 4];

function insert(arr, item, index) {
    arr = arr.reduce(function(s, a, i) {
      i == index ? s.push(item, a) : s.push(a);
      return s;
    }, []);   
    console.log(arr);
}

insert(arr, "banana", 1);
insert(arr2, 3, 2);


6

Voici deux façons:

const array = [ 'My', 'name', 'Hamza' ];

array.splice(2, 0, 'is');

console.log("Method 1 : ", array.join(" "));

OU

Array.prototype.insert = function ( index, item ) {
    this.splice( index, 0, item );
};

const array = [ 'My', 'name', 'Hamza' ];
array.insert(2, 'is');

console.log("Method 2 : ", array.join(" "));


4

Même si cela a déjà été répondu, j'ajoute cette note pour une approche alternative.

Je voulais placer un nombre connu d'éléments dans un tableau, dans des positions spécifiques, car ils sortent d'un "tableau associatif" (c'est-à-dire un objet) qui, par définition, n'est pas garanti d'être dans un ordre trié. Je voulais que le tableau résultant soit un tableau d'objets, mais les objets soient dans un ordre spécifique dans le tableau car un tableau garantit leur ordre. J'ai donc fait ça.

D'abord l'objet source, une chaîne JSONB récupérée de PostgreSQL. Je voulais le faire trier par la propriété "order" dans chaque objet enfant.

var jsonb_str = '{"one": {"abbr": "", "order": 3}, "two": {"abbr": "", "order": 4}, "three": {"abbr": "", "order": 5}, "initialize": {"abbr": "init", "order": 1}, "start": {"abbr": "", "order": 2}}';

var jsonb_obj = JSON.parse(jsonb_str);

Puisque le nombre de nœuds dans l'objet est connu, je crée d'abord un tableau avec la longueur spécifiée:

var obj_length = Object.keys(jsonb_obj).length;
var sorted_array = new Array(obj_length);

Et puis itérer l'objet, en plaçant les objets temporaires nouvellement créés dans les emplacements souhaités dans le tableau sans vraiment "tri".

for (var key of Object.keys(jsonb_obj)) {
  var tobj = {};
  tobj[key] = jsonb_obj[key].abbr;

  var position = jsonb_obj[key].order - 1;
  sorted_array[position] = tobj;
}

console.dir(sorted_array);

3

Quiconque a toujours des problèmes avec celui-ci et a essayé toutes les options ci-dessus et ne l'a jamais obtenu. Je partage ma solution, c'est pour prendre en considération que vous ne voulez pas énoncer explicitement les propriétés de votre objet par rapport au tableau.

function isIdentical(left, right){
    return JSON.stringify(left) === JSON.stringify(right);
}

function contains(array, obj){
    let count = 0;
    array.map((cur) => {
          if(this.isIdentical(cur, obj)) count++;
    });
    return count > 0;
}

Il s'agit d'une combinaison de l'itération du tableau de référence et de sa comparaison avec l'objet que vous souhaitez vérifier, convertissez-les tous les deux en une chaîne, puis répétez-les s'ils correspondent. Ensuite, vous pouvez simplement compter. Cela peut être amélioré mais c'est là que je me suis installé. J'espère que cela t'aides.


3

Profitant de la méthode de réduction comme suit:

function insert(arr, val, index) {
    return index >= arr.length 
        ? arr.concat(val)
        : arr.reduce((prev, x, i) => prev.concat(i === index ? [val, x] : x), []);
}

Donc, de cette façon, nous pouvons retourner un nouveau tableau (ce sera une façon fonctionnelle cool - bien mieux que d'utiliser push ou splice) avec l'élément inséré à l'index, et si l'index est supérieur à la longueur du tableau, il sera inséré à la fin.


3

Array#splice()est la voie à suivre, sauf si vous voulez vraiment éviter de muter le tableau. Étant donné 2 tableaux arr1et arr2, voici comment insérer le contenu de arr2dans arr1après le premier élément:

const arr1 = ['a', 'd', 'e'];
const arr2 = ['b', 'c'];

arr1.splice(1, 0, ...arr2); // arr1 now contains ['a', 'b', 'c', 'd', 'e']

console.log(arr1)

Si vous êtes préoccupé par la mutation du tableau (par exemple, si vous utilisez Immutable.js), vous pouvez utiliser à la place slice(), à ne pas confondre splice()avec a 'p'.

const arr3 = [...arr1.slice(0, 1), ...arr2, ...arr1.slice(1)];

2

J'ai essayé ça et ça marche bien!

var initialArr = ["India","China","Japan","USA"];
initialArr.splice(index, 0, item);

L'index est la position où vous souhaitez insérer ou supprimer l'élément. 0, c'est-à-dire que le deuxième paramètre définit le nombre d'éléments de l'index à supprimer. Ce sont les nouvelles entrées que vous voulez faire dans le tableau. Il peut en être un ou plusieurs.

initialArr.splice(2, 0, "Nigeria");
initialArr.splice(2, 0, "Australia","UK");

4
copiez simplement la réponse ci-dessus. cela n'ajoute aucune valeur à la question. soit vous ajoutez une nouvelle réponse ou un commentaire sur l'existant. veuillez essayer d'apporter quelque chose de nouveau. nous ne voulons pas gâcher cette communauté
hannad rehman

1

Voici une fonction de travail que j'utilise dans l'une de mes applications.

Ceci vérifie si la sortie de l'article

let ifExist = (item, strings = [ '' ], position = 0) => {
     // output into an array with empty string. Important just in case their is no item. 
    let output = [ '' ];
    // check to see if the item that will be positioned exist.
    if (item) {
        // output should equal to array of strings. 
        output = strings;
       // use splice in order to break the array. 
       // use positition param to state where to put the item
       // and 0 is to not replace an index. Item is the actual item we are placing at the prescribed position. 
        output.splice(position, 0, item);
    }
    //empty string is so we do not concatenate with comma or anything else. 
    return output.join("");
};

Et puis je l'appelle ci-dessous.

ifExist("friends", [ ' ( ', ' )' ], 1)}  // output: ( friends )
ifExist("friends", [ ' - '], 1)}  // output:  - friends 
ifExist("friends", [ ':'], 0)}  // output:   friends: 

1

Un peu d'un fil plus ancien, mais je dois être d'accord avec Redu ci-dessus car l'épissure a définitivement une interface confuse. Et la réponse donnée par cdbajorin selon laquelle "il ne renvoie un tableau vide que lorsque le deuxième paramètre est 0. S'il est supérieur à 0, il renvoie les éléments supprimés du tableau" est, bien que précise, prouvant le point. L'intention de la fonction est de raccorder ou, comme dit précédemment par Jakob Keller, "de se joindre ou de se connecter, également de changer. Vous avez un tableau établi que vous modifiez maintenant, ce qui impliquerait l'ajout ou la suppression d'éléments ...." Étant donné que, le la valeur de retour des éléments, le cas échéant, qui ont été supprimés est, au mieux, maladroite. Et je suis à 100% d'accord pour dire que cette méthode aurait pu être mieux adaptée au chaînage si elle avait renvoyé ce qui semble naturel, un nouveau tableau avec les éléments épissés ajoutés. Ensuite, vous pouvez faire des choses comme ["19", "17"]. Splice (1,0, "18"). Join ("...") ou tout ce que vous voulez avec le tableau renvoyé. Le fait qu'il retourne ce qui a été supprimé est juste un peu absurde à mon humble avis. Si l'intention de la méthode était de "découper un ensemble d'éléments" et que c'était seulement son intention, peut-être. Il semble que si je ne sais pas déjà ce que je coupe, j'ai probablement peu de raisons de couper ces éléments, n'est-ce pas? Il serait préférable qu'il se comporte comme concat, map, réduire, tranche, etc. où un nouveau tableau est fait à partir du tableau existant plutôt que de muter le tableau existant. Ce sont tous chaînables, et c'est un problème important. Il est plutôt courant de manipuler des tableaux en chaîne. On dirait que la langue doit aller dans l'une ou l'autre direction et essayer de s'y tenir le plus possible. Javascript étant fonctionnel et moins déclaratif, il semble juste être un étrange écart par rapport à la norme.


-2

Performance

Aujourd'hui (2020.04.24), j'effectue des tests pour les solutions choisies pour les petites et grandes baies. Je les ai testés sur MacOs High Sierra 10.13.6 sur Chrome 81.0, Safari 13.1, Firefox 75.0.

Conclusions

Pour tous les navigateurs

  • étonnamment pour les petites baies, les solutions non en place basées sur sliceet reduce(D, E, F) sont généralement 10x à 100x plus rapides que les solutions en place
  • pour les grands tableaux, les solutions sur place basées sur splice(AI, BI, CI) étaient les plus rapides (parfois ~ 100x - mais cela dépend de la taille du tableau)
  • pour les petites baies, la solution BI était la plus lente
  • pour les grands tableaux, la solution E était la plus lente

entrez la description de l'image ici

Détails

Les tests ont été divisés en deux groupes: solutions sur place (AI, BI, CI) et solutions non sur place (D, E, F) et ont été effectués pour deux cas

  • test de tableau avec 10 éléments - vous pouvez l'exécuter ICI
  • test de tableau avec 1.000.000 éléments - vous pouvez l'exécuter ICI

Le code testé est présenté dans l'extrait ci-dessous

Des exemples de résultats pour un petit tableau sur du chrome sont ci-dessous

entrez la description de l'image ici

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.