Estou tendo dificuldade para descobrir como mover um elemento da matriz. Por exemplo, considerando o seguinte:
var arr = [ 'a', 'b', 'c', 'd', 'e'];
Como posso escrever uma função para mover 'd'
antes 'b'
?
Ou 'a'
depois 'c'
?
Após a movimentação, os índices do restante dos elementos devem ser atualizados. Isso significa que no primeiro exemplo, após a movimentação, arr [0] seria = 'a', arr [1] = 'd' arr [2] = 'b', arr [3] = 'c', arr [4] = 'e'
Parece que deve ser bem simples, mas não consigo entender.
javascript
arrays
Mark Brown
fonte
fonte
const changeValuePosition = (arr, init, target) => {[arr[init],arr[target]] = [arr[target],arr[init]]; return arr}
init
etarget
.Respostas:
Se você deseja uma versão no npm, a movimentação da matriz é a mais próxima dessa resposta, embora não seja a mesma implementação. Veja sua seção de uso para mais detalhes. A versão anterior desta resposta (que modificou Array.prototype.move) pode ser encontrada no npm em array.prototype.move .
Eu tive um sucesso bastante bom com esta função:
Observe que o último
return
é simplesmente para fins de teste:splice
executa operações no array no local, portanto, um retorno não é necessário. Por extensão, estamove
é uma operação no local. Se você quiser evitar isso e retornar uma cópia, useslice
.Percorrendo o código:
new_index
for maior que o comprimento da matriz, queremos (presumo) que a matriz seja preenchida corretamente com novosundefined
s. Esse pequeno trecho lida com isso pressionandoundefined
a matriz até obtermos o comprimento adequado.arr.splice(old_index, 1)[0]
dividimos o elemento antigo.splice
retorna o elemento que foi emendado, mas está em uma matriz. No exemplo acima, isso foi[1]
. Então, pegamos o primeiro índice desse array para obter o raw1
lá.splice
para inserir esse elemento no lugar do new_index. Como preenchemos a matriz acima senew_index > arr.length
, provavelmente ela aparecerá no lugar certo, a menos que eles tenham feito algo estranho como passar em um número negativo.Uma versão mais sofisticada para contabilizar índices negativos:
O que deve dar conta de coisas como
array_move([1, 2, 3], -1, -2)
corretamente (mova o último elemento para o segundo para o último lugar). O resultado para isso deve ser[1, 3, 2]
.De qualquer forma, na sua pergunta original, você faria
array_move(arr, 0, 2)
paraa
depoisc
. Parad
antesb
, você fariaarray_move(arr, 3, 1)
.fonte
.hasOwnProperty
verificação ao iterar com coisas como for..in, especialmente com bibliotecas como Prototype e MooTools que modificam protótipos. De qualquer forma, não achei que fosse uma questão particularmente importante em um exemplo relativamente limitado como esse, e há uma boa divisão na comunidade sobre se a modificação do protótipo é ou não uma boa idéia. Normalmente, os problemas de iteração são a menor preocupação.this[new_index] = undefined;
dentro doif
bloco. Como as matrizes Javascript são escassas, isso estenderá o tamanho da matriz para incluir o new_index para o.splice
trabalho, mas sem a necessidade de criar nenhum elemento intermediário.this[new_index] = undefined
, na verdade, colocar umundefined
slot na matriz antes do índice correto. (Por exemplo,[1,2,3].move(0,10)
terá1
no slot 10 eundefined
no slot 9.) Em vez disso, se a escassez estiver boa, poderíamos ficarthis[new_index] = this.splice(old_index, 1)[0]
sem a outra chamada de emenda (transformá-lo em um if / else).Aqui está um liner que eu encontrei no JSPerf ....
o que é incrível de ler, mas se você quiser desempenho (em pequenos conjuntos de dados), tente ...
Eu não posso aceitar nenhum crédito, tudo deve ir para Richard Scarrott . Ele supera o método baseado em emenda para conjuntos de dados menores neste teste de desempenho . No entanto, é significativamente mais lento em conjuntos de dados maiores, como aponta Darwayne .
fonte
from >= to ? this.splice(to, 0, this.splice(from, 1)[0]) : this.splice(to - 1, 0, this.splice(from, 1)[0]);
Eu gosto desse jeito. É conciso e funciona.
Nota: lembre-se sempre de verificar os limites do seu array.
Executar Snippet no jsFiddle
fonte
como a função é encadeada, isso também funciona:
demonstração aqui
fonte
Meu 2c. Fácil de ler, funciona, é rápido, não cria novas matrizes.
fonte
array
, como foi feito no final.Com a idéia de @Reid, tive a ideia de colocar algo no lugar do item que deveria ser movido para manter o tamanho da matriz constante. Isso simplifica os cálculos. Além disso, empurrar um objeto vazio tem os benefícios adicionais de poder procurá-lo exclusivamente posteriormente. Isso funciona porque dois objetos não são iguais até que estejam se referindo ao mesmo objeto.
Então, aqui está a função que recebe a matriz de origem e a fonte, os índices de destino. Você pode adicioná-lo ao Array.prototype, se necessário.
fonte
sourceIndex = 0
,destIndex = 1
destIndex
deve ser o índice antes que o elemento de origem seja movido na matriz.Isso é baseado na solução da @ Reid. Exceto:
Array
protótipo.undefined
itens, apenas move o item para a posição mais à direita.Função:
Testes unitários:
fonte
Aqui está minha solução ES6 de um liner com um parâmetro opcional
on
.Adaptação da primeira solução proposta por
digiguru
O parâmetro
on
é o número de elementos quefrom
você deseja mover.fonte
O
splice
método deArray
pode ajudar: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/spliceLembre-se de que pode ser relativamente caro, pois precisa re-indexar ativamente a matriz.
fonte
Uma abordagem seria criar uma nova matriz com as peças na ordem desejada, usando o método de fatia.
Exemplo
fonte
arr2
acaba sendo uma string devido às operações de concatenação, certo? :) acaba sendo"adc,de"
.Você pode implementar algum cálculo básico e criar uma função universal para mover o elemento da matriz de uma posição para outra.
Para JavaScript, é assim:
Confira "mover elementos da matriz" em "gloommatter" para obter explicações detalhadas.
http://www.gloommatter.com/DDesign/programming/moving-any-array-elements-universal-function.html
fonte
Eu implementei uma
ECMAScript 6
solução imutável baseada na@Merc
resposta de aqui:Os nomes das variáveis podem ser encurtados, apenas os longos, para que o código possa se explicar.
fonte
array
imediatamente sefromIndex === toIndex
, e apenas criar onewArray
se não for o caso? Imutabilidade não significa que uma nova cópia deve ser criada por chamada de função, mesmo quando não há alterações. Apenas pedir a b / c o motivo para o aumento do comprimento dessa função (em relação às linhas de base baseadas em emenda) é desempenho efromIndex
pode muito bem ser igualtoIndex
, dependendo do uso.Eu precisava de um método de movimento imutável (que não alterasse a matriz original), então adaptei a resposta aceita de @ Reid para simplesmente usar Object.assign para criar uma cópia da matriz antes de fazer a emenda.
Aqui está um jsfiddle mostrando-o em ação .
fonte
http://plnkr.co/edit/JaiAaO7FQcdPGPY6G337?p=preview
fonte
Acabei combinando dois deles para trabalhar um pouco melhor ao mover distâncias pequenas e grandes. Eu obtenho resultados bastante consistentes, mas isso provavelmente poderia ser modificado um pouco por alguém mais inteligente do que eu para trabalhar de maneira diferente em tamanhos diferentes etc.
O uso de alguns dos outros métodos ao mover objetos pequenas distâncias foi significativamente mais rápido (x10) do que o uso de emenda. Porém, isso pode variar dependendo dos comprimentos da matriz, mas é verdade para matrizes grandes.
http://jsperf.com/arraymove-many-sizes
fonte
Afirma-se em muitos lugares ( adicionar funções personalizadas ao Array.prototype ) jogar com o protótipo Array pode ser uma má idéia, de qualquer maneira eu combinei o melhor de várias postagens, vim com isso usando o Javascript moderno:
A esperança pode ser útil para qualquer pessoa
fonte
Esta versão não é ideal para todos os fins, e nem todo mundo gosta de expressões de vírgula, mas aqui está uma linha que é uma expressão pura, criando uma nova cópia:
Uma versão com um pouco de desempenho aprimorado retorna a matriz de entrada se nenhuma movimentação for necessária, ainda assim é aceitável para uso imutável, pois a matriz não muda e ainda é uma expressão pura:
A invocação de qualquer um é
ou seja, depende da propagação para gerar uma nova cópia. O uso de uma aridade fixa 3
move
colocaria em risco a propriedade de expressão única, a natureza não destrutiva ou o benefício de desempenhosplice
. Novamente, é mais um exemplo que atende a alguns critérios do que uma sugestão para uso em produção.fonte
Array.move.js
Sumário
Move elementos dentro de uma matriz, retornando uma matriz contendo os elementos movidos.
Sintaxe
Parâmetros
index : Índice no qual mover elementos. Se negativo, o índice começará do final.
howMany : Número de elementos para mover do índice .
toIndex : Índice da matriz na qual colocar os elementos movidos. Se negativo, o toIndex começará do final.
Uso
Polyfill
fonte
.move
pareça que funcione (não testei), observe que não faz parte de nenhum padrão. Também é bom avisar às pessoas que as funções polyfill / monkeypatched podem quebrar algum código que assume que tudo o que é enumerável é deles.Usei a boa resposta de @Reid , mas tive dificuldade em mover um elemento do final de uma matriz um passo adiante - para o início (como em um loop ). Por exemplo, ['a', 'b', 'c'] deve se tornar ['c', 'a', 'b'] chamando .move (2,3)
Consegui isso alterando o caso de new_index> = this.length.
fonte
Como complemento à excelente resposta de Reid (e porque não posso comentar); Você pode usar o módulo para fazer com que índices negativos e índices muito grandes "rolem":
fonte
fonte
Eu pensei que este era um problema de troca, mas não é. Aqui está minha solução de uma linha:
Aqui está um pequeno teste:
fonte
resultado:
fonte
fonte
fonte
Versão imutável sem cópia de matriz:
fonte
Eu acho que a melhor maneira é definir uma nova propriedade para Arrays
fonte
Outra variante JS pura usando o operador de espalhamento de matriz ES6 sem mutação
fonte
Este método preserva a matriz original e verifica se há erros de delimitação.
fonte