Como inserir um item em uma matriz em um índice específico (JavaScript)?

2931

Estou procurando um método de inserção de matriz JavaScript, no estilo de:

arr.insert(index, item)

De preferência no jQuery, mas qualquer implementação em JavaScript funcionará neste momento.

tags2k
fonte
96
Observe que o JQuery é uma biblioteca de manipulação de eventos e DOM, não uma linguagem própria. Não tem nada a ver com manipulação de array.
Domino
25
api.jquery.com/jQuery.inArray não tem nada a ver com o DOM ou os eventos. O jQuery evoluiu para um kit de ferramentas misto para o desenvolvimento de JS do navegador, levando as pessoas a esperar que ele tivesse um método para tudo.
Tim
4
@ Tim, mas ainda não é uma linguagem própria (ainda há algumas perguntas como "Como a soma de dois números em jQuery" aqui no SO)
Victor
3
@ Victor Não, e nunca será. O jQuery foi útil e relevante, mas já teve seu dia.
Tim
1
Além disso, veja isto , para uma surpresa distorcida (:
noobie

Respostas:

4756

O que você deseja é a splicefunção no objeto de matriz nativa.

arr.splice(index, 0, item);irá inserir itemem arrno índice especificado (excluindo 0itens em primeiro lugar, que é, é apenas uma inserção).

Neste exemplo, criaremos uma matriz e adicionaremos um elemento a ela no índice 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());

tvanfosson
fonte
168
Obrigado, pensei que me sentiria estúpido por perguntar, mas agora que sei a resposta, não sei! Por que diabos eles decidiram chamá-lo de emenda quando um termo mais pesquisável era de uso comum para a mesma função ?!
Tags2k 25/02/09
83
@ tags2k: porque a função faz mais do que inserir itens e seu nome já foi estabelecido em perl?
2540 Christoph
55
Splice pode inserir, mas com a mesma frequência não . Por exemplo: arr.splice(2,3)removerá 3 elementos começando no índice 2. Sem passar o terceiro .... Nésimo parâmetro, nada é inserido. Portanto, o nome insert()também não faz justiça.
EBarr
14
Eu acho que o termo "emenda" faz sentido. Emenda significa unir-se ou conectar-se, também para mudar. Você tem uma matriz estabelecida que agora está "alterando", o que envolveria adicionar ou remover elementos. Você especifica onde na matriz iniciar, quantos itens antigos remover (se houver) e, por último, opcionalmente, uma lista de novos elementos a serem adicionados. Splice também é um ótimo termo de ficção científica, é claro.
Jakub Keller
286

Você pode implementar o Array.insertmétodo fazendo o seguinte:

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

Então você pode usá-lo como:

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

// => arr == [ 'A', 'B', 'C', 'D', 'E' ]
FrEsC 81
fonte
9
Para inserir vários itens, você pode usarArray.prototype.insert = function (index, items) { this.splice.apply(this, [index, 0].concat(items)); }
Ryan Smith
7
O problema com a adição de itens à matriz é que a função aparecerá como um elemento quando você fizer para (i in arr) {...}
rep_movsd
7
Mas lembre-se de que não é recomendável estender tipos nativos, pois isso pode interferir em outro código ou funcionalidade futura.
marsze
17
Não modifique objetos que você não possui
Luis Cabrera Benito
4
Não modifique protótipos
satya164
141

Além da emenda, você pode usar essa abordagem que não altera a matriz original, mas cria uma nova matriz com o item adicionado. Você deve evitar a mutação sempre que possível. Estou usando o operador de propagação ES6 aqui.

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]

Isso pode ser usado para adicionar mais de um item, aprimorando um pouco a função para usar o operador restante para os novos itens e espalhá-lo no resultado retornado também

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]

gafi
fonte
1
Essa é uma maneira boa e segura de fazer isso? Eu pergunto porque isso parece tão elegante e conciso, mas nenhuma outra resposta toca nisso. A maioria deles modifica o objeto protótipo!
Harsh Kanchina
5
@HarshKanchina Isso provavelmente é porque a maioria das respostas é anterior ao ES6, mas essa abordagem é muito comum agora pela minha experiência
GAFI
77

insertMétodos de matriz personalizados

1. Com vários argumentos e suporte a encadeamento

/* 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;
};

Pode inserir vários elementos (como nativo splice faz) e suporta encadeamento:

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

2. Com argumentos do tipo array, mesclando e encadeando o suporte

/* 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;
};

Ele pode mesclar matrizes dos argumentos com a matriz fornecida e também suporta encadeamento:

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

DEMO: http://jsfiddle.net/UPphH/

Visão
fonte
Existe uma maneira compacta de ter essa versão também mesclar uma matriz quando encontrar uma nos argumentos?
Nolo 30/03
Eu não entendo o primeiro resultado ["b", "X", "Y", "Z", "c"]. Por que não está "d"incluído? Parece-me que se você colocar 6 como o segundo parâmetro de slice()e houver 6 elementos na matriz a partir do índice especificado, deverá obter todos os 6 elementos no valor de retorno. (O documento diz howManypara esse parâmetro.) Developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…
Alexis Wilke
Na verdade, se eu usar um índice de 3 ou mais, eu não recebem nada na saída (caso 1., FireFox) ["a", "b", "c", "d"].insert(2, "X", "Y", "Z").slice(3, 3);=>[ ]
Alexis Wilke
@AlexisWilke No primeiro exemplo, usei o slicemétodo e não splice, ao qual você está se referindo no comentário. O segundo parâmetro de slice(nomeado end) é o índice baseado em zero no qual finalizar a extração. sliceextrai até, mas não incluiend . Portanto, depois de insertter ["a", "b", "X", "Y", "Z", "c", "d"], a partir do qual sliceextrai elementos com índices de 1até 6, ou seja, de "b"até, "d"mas não incluindo "d". Isso faz sentido?
VisioN
41

Se você deseja inserir vários elementos em uma matriz de uma só vez, confira esta resposta do Stack Overflow: Uma maneira melhor de unir uma matriz em uma matriz em javascript

Também aqui estão algumas funções para ilustrar os dois exemplos:

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

Finalmente, aqui está um jsFiddle para que você possa ver por si mesmo: http://jsfiddle.net/luisperezphd/Wc8aS/

E é assim que você usa as funções:

// 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);
Luis Perez
fonte
1
InsertAt () não seria melhor chamar insertArrayAt () depois de criar um arrayToInsert de elemento único? Isso evita a repetição de código idêntico.
Matt Sach
1
este é um ótimo exemplo de quando usar 'aplicar'
CRice
Adicionei um parâmetro removeCount a esse método para aproveitar as vantagens da capacidade do splice de remover itens também nesse índice: Array.prototype.splice.apply (array, [index, removeCount || 0] .concat (arrayToInsert));
CRice
23

Para programação funcional adequada e propósitos de encadeamento, uma invenção Array.prototype.insert()é essencial. Na verdade, a emenda poderia ter sido perfeita se tivesse retornado a matriz mutada em vez de uma matriz vazia totalmente sem sentido. Então aqui vai

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

Bem, o que foi dito acima Array.prototype.splice()muda com a matriz original e alguns podem reclamar como "você não deve modificar o que não lhe pertence" e isso pode acabar se tornando correto também. Então, para o bem-estar público, gostaria de dar outro Array.prototype.insert()que não modifique a matriz original. Aqui vai;

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

Redu
fonte
2
"uma matriz vazia totalmente sem sentido" - ela retorna apenas uma matriz vazia quando o segundo parâmetro é 0. Se for maior que 0, retorna os itens removidos da matriz. Como você está adicionando um protótipo e splicemodifica a matriz original, não acho que a "programação funcional apropriada" pertença a nenhum lugar nas proximidades splice.
Chrisbajorin
Estamos falando de inserção aqui e o segundo parâmetro de Array.prototype.splice () deve ser zero. E o que ele retorna não tem outro significado além de "eu não excluí nada" e, como o usamos para inserir um item, já temos essas informações. Se você não quiser alterar a matriz original, poderá fazer o mesmo com duas operações Array.prototype.slice () e uma Array.prototype.concat (). Você decide.
Redu 22/05
1
Sua segunda implementação é a mais limpa de toda a página e você tem zero votos. Por favor, pegue o meu e continue com o bom trabalho. (você deve apenas evitar a mutação do protótipo, mas você já sabe que)
Niko
1
Eu acho que vale a pena mencionar que o parâmetro resto é o novo ECMA 6º ( developer.mozilla.org/en/docs/Web/JavaScript/Reference/… ) #
9776 Geza Turi
18

Eu recomendo usar JavaScript puro neste caso, também não há método de inserção em JavaScript, mas temos um método que é um método Array interno que faz o trabalho para você, chamado de emenda ...

Vamos ver o que é splice () ...

O método splice () altera o conteúdo de uma matriz removendo os elementos existentes e / ou adicionando novos elementos.

OK, imagine que temos esta matriz abaixo:

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

Podemos remover 3assim:

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

Ele retornará 3, mas se verificarmos o arr agora, temos:

[1, 2, 4, 5]

Até agora, tudo bem, mas como podemos adicionar um novo elemento à matriz usando emenda? Vamos colocar de volta 3 no arr ...

arr.splice(2, 0, 3);

Vamos ver o que fizemos ...

Usamos emenda novamente, mas desta vez para o segundo argumento, passamos 0 , significa que não queremos excluir nenhum item, mas, ao mesmo tempo, adicionamos o terceiro argumento, que é 3, que será adicionado no segundo índice ...

Você deve estar ciente de que podemos excluir e adicionar ao mesmo tempo, por exemplo, agora podemos fazer:

arr.splice(2, 2, 3);

O que excluirá 2 itens no índice 2, depois adicionará 3 no índice 2 e o resultado será:

[1, 2, 3, 5];

Isso está mostrando como cada item da emenda funciona:

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

Alireza
fonte
13

Anexar elemento único a um índice específico

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

Anexar vários elementos em um índice específico

//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
Srikrushna
fonte
8
Vale notar que o arrName [3] não anexa, substitui.
Sfratini # 10/18
Ele adiciona o elemento à matriz existente sem sobrecarregar, Ex: let arrName = ['xxx', 'yyy', 'zzz']; arrName.splice (1, 0, 'aaa', 'bbb', 'ccc'); depois de imprimir o arrName
Srikrushna 12/12
Se arrName tiver mais de 3 elementos, você estará substituindo o terceiro, não anexando. Ou estou olhando isso da maneira errada?
sfratini 12/09
Se inserirmos um elemento no meio, ele mudará o próximo elemento para não substituir. Especifique o seu problema, o que você precisa. Pegue uma matriz (exemplo) e o que você precisa na saída. plz comentar me
Srikrushna
1
@Srikrushna arrName[3] = 'newName1';será acrescentado se a matriz tiver apenas 3 elementos. Se houver um elemento no índice 3, este será substituído. Se você quiser acrescentar no final, é melhor usararrName.push('newName1');
temor
6

Outra solução possível, com o uso 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);

usuário gentil
fonte
6

Aqui estão duas maneiras:

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(" "));

M. Hamza Rajput
fonte
4

Mesmo que isso já tenha sido respondido, estou adicionando esta nota para uma abordagem alternativa.

Eu queria colocar um número conhecido de itens em uma matriz, em posições específicas, pois elas saem de uma "matriz associativa" (isto é, um objeto) que, por definição, não é garantido que esteja em uma ordem classificada. Eu queria que a matriz resultante fosse uma matriz de objetos, mas os objetos estivessem em uma ordem específica na matriz, já que uma matriz garante sua ordem. Então eu fiz isso.

Primeiro, o objeto de origem, uma string JSONB recuperada do PostgreSQL. Eu queria que ele fosse classificado pela propriedade "order" em cada objeto filho.

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

Como o número de nós no objeto é conhecido, primeiro crio uma matriz com o comprimento especificado:

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

E, em seguida, itere o objeto, colocando os objetos temporários recém-criados nos locais desejados na matriz, sem que ocorra realmente uma "classificação".

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);
Ville
fonte
3

Qualquer um que ainda esteja tendo problemas com esse problema, tentou todas as opções acima e nunca conseguiu. Estou compartilhando minha solução, isso é para levar em consideração que você não deseja declarar explicitamente as propriedades do seu objeto versus a matriz.

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

Essa é uma combinação de iterar a matriz de referência e compará-la com o objeto que você deseja verificar, converter os dois em uma sequência e iterar se corresponder. Então você pode apenas contar. Isso pode ser melhorado, mas é aqui que eu me acomodo. Espero que isto ajude.

Clyde
fonte
3

Tendo lucro do método de redução da seguinte forma:

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

Dessa forma, podemos retornar uma nova matriz (será uma maneira funcional legal - muito melhor do que usar push ou emenda) com o elemento inserido no índice e, se o índice for maior que o comprimento da matriz, ele será inserido no fim.

alejoko
fonte
3

Array#splice()é o caminho a seguir, a menos que você realmente queira evitar a mutação da matriz. Dado 2 matrizes arr1e arr2, aqui está como você iria inserir o conteúdo de arr2dentro arr1após o primeiro elemento:

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)

Se você estiver preocupado em alterar a matriz (por exemplo, se estiver usando o Immutable.js), poderá usar slice(), para não confundir splice()com a 'p'.

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

Eu tentei isso e está funcionando bem!

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

Índice é a posição em que você deseja inserir ou excluir o elemento. 0 ou seja, o segundo parâmetro define o número de elemento do índice a ser removido. As novas entradas que você deseja criar na matriz. Pode ser um ou mais de um.

initialArr.splice(2, 0, "Nigeria");
initialArr.splice(2, 0, "Australia","UK");
Pawan
fonte
4
basta copiar e colar a resposta acima. isso não está agregando valor à pergunta. adicione uma nova resposta ou comente a existente. por favor, tente contribuir com algo novo. Nós não queremos estragar esta comunidade
rehman hannad
1

Aqui está uma função que eu uso em um dos meus aplicativos.

Isso verifica se o item sai

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("");
};

E então eu chamo isso abaixo.

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

Um pouco mais antigo, mas tenho que concordar com o Redu acima porque o splice definitivamente tem uma interface um pouco confusa. E a resposta dada por cdbajorin de que "ele retorna apenas uma matriz vazia quando o segundo parâmetro é 0. Se for maior que 0, retorna os itens removidos da matriz" está, enquanto preciso, provando o ponto. A intenção da função é unir ou, como já foi dito por Jakob Keller, "unir-se ou conectar-se, também para alterar. Você tem uma matriz estabelecida que agora está mudando, o que envolveria adicionar ou remover elementos ...". o valor de retorno dos elementos, se houver, que foram removidos é, na melhor das hipóteses, estranho. E eu 100% concorda que esse método poderia ser mais adequado ao encadeamento se tivesse retornado o que parece natural, uma nova matriz com os elementos emendados adicionados. Depois, você pode fazer coisas como ["19", "17"]. Splice (1,0, "18"). Join ("...") ou o que quiser com a matriz retornada. O fato de que ele retorna o que foi removido é meio que IMHO sem sentido. Se a intenção do método era "cortar um conjunto de elementos" e essa era a única intenção, talvez. Parece que, se eu ainda não sei o que estou cortando, provavelmente tenho poucas razões para cortar esses elementos, não é? Seria melhor se ele se comportasse como concat, mapear, reduzir, cortar, etc., onde uma nova matriz é feita a partir da matriz existente, em vez de mudar a matriz existente. Tudo isso é encadeado e isso é um problema significativo. É bastante comum a manipulação de array em cadeia. Parece que o idioma precisa seguir uma direção ou outra e tentar cumpri-lo o máximo possível. Javascript sendo funcional e menos declarativo, parece apenas um desvio estranho da norma.

meem
fonte
-2

atuação

Hoje (2020.04.24) realizo testes para soluções escolhidas para matrizes grandes e pequenas. Testei-os no MacOs High Sierra 10.13.6 no Chrome 81.0, Safari 13.1, Firefox 75.0.

Conclusões

Para todos os navegadores

  • surpreendentemente para pequenas matrizes, soluções não no local, baseadas sliceereduce (D, E, F) são geralmente 10x-100x mais rápido do que as soluções em-lugar
  • para grandes matrizes, as soluções no local baseadas em splice (AI, BI, CI) foram as mais rápidas (às vezes ~ 100x - mas isso depende do tamanho da matriz)
  • para matrizes pequenas, a solução de BI foi a mais lenta
  • para grandes matrizes A solução E foi a mais lenta

insira a descrição da imagem aqui

Detalhes

Os testes foram divididos em dois grupos: soluções no local (AI, BI, CI) e soluções não no local (D, E, F) e foram realizados em dois casos

  • teste para array com 10 elementos - você pode executá-lo AQUI
  • teste para array com 1.000.000 de elementos - você pode executá-lo AQUI

O código testado é apresentado no snippet abaixo

Os resultados de exemplo para matriz pequena no chrome estão abaixo

insira a descrição da imagem aqui

Kamil Kiełczewski
fonte