Me está costando descubrir cómo mover un elemento de matriz. Por ejemplo, dado lo siguiente:
var arr = [ 'a', 'b', 'c', 'd', 'e'];
¿Cómo puedo escribir una función para moverme 'd'
antes 'b'
?
O 'a'
despues 'c'
?
Después del movimiento, los índices del resto de los elementos deben actualizarse. Esto significa en el primer ejemplo después del movimiento arr [0] would = 'a', arr [1] = 'd' arr [2] = 'b', arr [3] = 'c', arr [4] = 'mi'
Parece que debería ser bastante simple, pero no puedo entenderlo.
javascript
arrays
Mark Brown
fuente
fuente
const changeValuePosition = (arr, init, target) => {[arr[init],arr[target]] = [arr[target],arr[init]]; return arr}
init
ytarget
.Respuestas:
Si desea una versión en npm, array-move es la más cercana a esta respuesta, aunque no es la misma implementación. Vea su sección de uso para más detalles. La versión anterior de esta respuesta (que modificó Array.prototype.move) se puede encontrar en npm en array.prototype.move .
Tuve bastante éxito con esta función:
Tenga en cuenta que el último
return
es simplemente para fines de prueba:splice
realiza operaciones en la matriz en el lugar, por lo que no es necesario un retorno. Por extensión, estamove
es una operación en el lugar. Si desea evitar eso y devolver una copia, useslice
.Recorriendo el código:
new_index
es mayor que la longitud de la matriz, queremos (supongo) rellenar la matriz correctamente con nuevosundefined
s. Este pequeño fragmento maneja esto presionandoundefined
la matriz hasta que tengamos la longitud adecuada.arr.splice(old_index, 1)[0]
, empalmamos el viejo elemento.splice
devuelve el elemento que se empalmó, pero está en una matriz. En nuestro ejemplo anterior, esto fue[1]
. Así que tomamos el primer índice de esa matriz para obtener la materia prima1
allí.splice
para insertar este elemento en el lugar del nuevo_índice. Dado que rellenamos la matriz anterior sinew_index > arr.length
, probablemente aparecerá en el lugar correcto, a menos que hayan hecho algo extraño como pasar un número negativo.Una versión más elegante para tener en cuenta los índices negativos:
Lo que debería tener en cuenta cosas como
array_move([1, 2, 3], -1, -2)
correctamente (mover el último elemento al segundo al último lugar). Resultado para eso debería ser[1, 3, 2]
.De cualquier manera, en su pregunta original, lo haría
array_move(arr, 0, 2)
paraa
despuésc
. Parad
antesb
, lo haríasarray_move(arr, 3, 1)
.fuente
.hasOwnProperty
verificación al iterar con cosas como for..in, especialmente con bibliotecas como Prototype y MooTools que modifican los prototipos. De todos modos, no sentí que fuera un tema particularmente importante en un ejemplo relativamente limitado como este, y hay una buena división en la comunidad sobre si la modificación del prototipo es una buena idea. Sin embargo, normalmente los problemas de iteración son la menor preocupación.this[new_index] = undefined;
dentro delif
bloque. Como las matrices de Javascript son escasas, esto ampliará el tamaño de la matriz para incluir new_index para.splice
que funcione, pero sin necesidad de crear ningún elemento intermedio.this[new_index] = undefined
realmente colocará unundefined
en la ranura de la matriz antes del índice correcto. (Por ejemplo,[1,2,3].move(0,10)
tendrá1
en la ranura 10 yundefined
en la ranura 9.) Más bien, si la dispersión está bien, podríamosthis[new_index] = this.splice(old_index, 1)[0]
prescindir de la otra llamada de empalme (en su lugar, haga un if / else).Aquí hay un trazador de líneas que encontré en JSPerf ...
que es increíble de leer, pero si quieres rendimiento (en pequeños conjuntos de datos) prueba ...
No puedo tomar ningún crédito, todo debería ir a Richard Scarrott . Es mejor que el método basado en empalmes para conjuntos de datos más pequeños en esta prueba de rendimiento . Sin embargo, es significativamente más lento en conjuntos de datos más grandes como señala Darwayne .
fuente
from >= to ? this.splice(to, 0, this.splice(from, 1)[0]) : this.splice(to - 1, 0, this.splice(from, 1)[0]);
Me gusta de esta manera. Es conciso y funciona.
Nota: recuerde siempre verificar los límites de su matriz.
Ejecute Snippet en jsFiddle
fuente
Como la función es encadenable, esto también funciona:
demostración aquí
fuente
Mi 2c. Fácil de leer, funciona, es rápido, no crea nuevas matrices.
fuente
array
, como lo hizo al final.Tengo la idea de @Reid de empujar algo en el lugar del elemento que se supone que debe moverse para mantener constante el tamaño de la matriz. Eso simplifica los cálculos. Además, empujar un objeto vacío tiene los beneficios adicionales de poder buscarlo de manera única más adelante. Esto funciona porque dos objetos no son iguales hasta que se refieren al mismo objeto.
Así que aquí está la función que toma la matriz fuente, y la fuente, los índices de destino. Puede agregarlo al Array.prototype si es necesario.
fuente
sourceIndex = 0
,destIndex = 1
destIndex
está destinado a ser el índice antes de que el elemento fuente se mueva en la matriz.Esto se basa en la solución de @ Reid. Excepto:
Array
prototipo.undefined
elementos, solo mueve el elemento a la posición más a la derecha.Función:
Pruebas unitarias:
fuente
Aquí está mi solución ES6 one liner con un parámetro opcional
on
.Adaptación de la primera solución propuesta por
digiguru
El parámetro
on
es el número de elementos a partir de losfrom
que desea mover.fuente
El
splice
método deArray
podría ayudar: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/spliceSolo tenga en cuenta que puede ser relativamente costoso ya que tiene que volver a indexar activamente la matriz.
fuente
Un enfoque sería crear una nueva matriz con las piezas en el orden que desee, utilizando el método de corte.
Ejemplo
fuente
arr2
termina siendo una cadena debido a las operaciones de concatenación, ¿verdad? :) Termina siendo"adc,de"
.Puede implementar algunos cálculos básicos y crear una función universal para mover elementos de matriz de una posición a otra.
Para JavaScript se ve así:
Consulte "elementos de matriz en movimiento" en "gloommatter" para obtener una explicación detallada.
http://www.gloommatter.com/DDesign/programming/moving-any-array-elements-universal-function.html
fuente
He implementado una
ECMAScript 6
solución inmutable basada en@Merc
la respuesta de aquí:Los nombres de las variables se pueden acortar, solo se usan los largos para que el código pueda explicarse por sí mismo.
fuente
array
inmediatamente sifromIndex === toIndex
, y solo crear elnewArray
si no es el caso? La inmutabilidad no significa que se deba crear una copia nueva por llamada a la función, incluso cuando no haya cambios. Solo preguntarle a b / c el motivo del aumento de la longitud de esta función (en relación con las líneas simples basadas en empalmes) es el rendimiento, y afromIndex
menudo puede ser igualtoIndex
, dependiendo del uso.Necesitaba un método de movimiento inmutable (uno que no cambiara la matriz original), así que adapté la respuesta aceptada de @ Reid para simplemente usar Object.assign para crear una copia de la matriz antes de hacer el empalme.
Aquí hay un jsfiddle que lo muestra en acción .
fuente
http://plnkr.co/edit/JaiAaO7FQcdPGPY6G337?p=preview
fuente
Terminé combinando dos de estos para trabajar un poco mejor al mover distancias pequeñas y grandes. Obtengo resultados bastante consistentes, pero esto probablemente podría ser modificado un poco por alguien más inteligente que yo para trabajar de manera diferente para diferentes tamaños, etc.
El uso de algunos de los otros métodos al mover objetos a distancias pequeñas fue significativamente más rápido (x10) que el uso del empalme. Sin embargo, esto puede cambiar dependiendo de la longitud de la matriz, pero es cierto para matrices grandes.
http://jsperf.com/arraymove-many-sizes
fuente
Se dice que en muchos lugares ( agregar funciones personalizadas en Array.prototype ) jugar con el prototipo Array podría ser una mala idea, de todos modos combiné lo mejor de varias publicaciones, vine con esto, usando Javascript moderno:
La esperanza puede ser útil para cualquiera
fuente
Esta versión no es ideal para todos los propósitos, y no a todos les gustan las expresiones de coma, pero aquí hay una frase que es pura expresión, creando una copia nueva:
Una versión ligeramente mejorada de rendimiento devuelve la matriz de entrada si no se necesita mover, todavía está bien para un uso inmutable, ya que la matriz no cambiará, y sigue siendo una expresión pura:
La invocación de cualquiera es
es decir, se basa en la difusión para generar una copia nueva. El uso de una aridad fija 3
move
pondría en peligro la propiedad de expresión única, o la naturaleza no destructiva, o el beneficio de rendimiento desplice
. Nuevamente, es más un ejemplo que cumple algunos criterios que una sugerencia para el uso de producción.fuente
Array.move.js
Resumen
Mueve elementos dentro de una matriz, devolviendo una matriz que contiene los elementos movidos.
Sintaxis
Parámetros
index : índice en el que mover elementos. Si es negativo, el índice comenzará desde el final.
howMany : número de elementos para mover desde el índice .
toIndex : índice de la matriz en la que colocar los elementos movidos. Si es negativo, toIndex comenzará desde el final.
Uso
Polyfill
fuente
.move
parece que debería funcionar (no lo he probado), debe tener en cuenta que no es parte de ningún estándar. También es bueno advertir a la gente que las funciones polyfill / monkeypatched pueden romper algún código que asume que todo lo enumerable es suyo.Utilicé la buena respuesta de @Reid , pero tuve problemas para mover un elemento desde el final de una matriz un paso más allá, hasta el principio (como en un bucle ). Por ejemplo, ['a', 'b', 'c'] debería convertirse en ['c', 'a', 'b'] llamando a .move (2,3)
Lo logré cambiando el caso de new_index> = this.length.
fuente
Como una adición a la excelente respuesta de Reid (y porque no puedo comentar); Puede usar el módulo para hacer que tanto los índices negativos como los índices demasiado grandes "pasen":
fuente
fuente
Pensé que esto era un problema de intercambio, pero no lo es. Aquí está mi solución de una línea:
Aquí hay una pequeña prueba:
fuente
resultado:
fuente
fuente
fuente
Versión inmutable sin copia de matriz:
fuente
Creo que la mejor manera es definir una nueva propiedad para Arrays
fuente
Otra variante pura de JS que usa el operador de propagación de matriz ES6 sin mutación
fuente
Este método preservará la matriz original y verificará los errores delimitadores.
fuente