Reordenación de matrices

98

Diga, tengo una matriz que se ve así:

var playlist = [
    {artist:"Herbie Hancock", title:"Thrust"},
    {artist:"Lalo Schifrin", title:"Shifting Gears"},
    {artist:"Faze-O", title:"Riding High"}
];

¿Cómo puedo mover un elemento a otra posición?

Quiero moverme, por ejemplo, {artist:"Lalo Schifrin", title:"Shifting Gears"}hasta el final.

Intenté usar empalme, así:

var tmp = playlist.splice(2,1);
playlist.splice(2,0,tmp);

Pero no funciona.

Wurlitzer
fuente
3
¿Qué significa "no funciona" - arroja un error, no cambia nada, cambia su matriz de una manera que no pretendía? Me parece razonable.
Jacob Mattison

Respuestas:

220

La sintaxis de Array.splicees:

yourArray.splice(index, howmany, element1, /*.....,*/ elementX);

Dónde:

  • índice es la posición en la matriz de la que desea comenzar a eliminar elementos
  • cuántos es cuántos elementos desea eliminar del índice
  • element1, ..., elementX son elementos que desea insertar desde el índice de posición .

Esto significa que splice()se puede usar para eliminar elementos, agregar elementos o reemplazar elementos en una matriz, según los argumentos que pase.

Tenga en cuenta que devuelve una matriz de los elementos eliminados.

Algo agradable y genérico sería:

Array.prototype.move = function (from, to) {
  this.splice(to, 0, this.splice(from, 1)[0]);
};

Entonces solo usa:

var ar = [1,2,3,4,5];
ar.move(0,3);
alert(ar) // 2,3,4,1,5

Diagrama:

Diagrama de algoritmo

Mate
fuente
17
Esta es una buena respuesta, y el empalme () dentro de un empalme () hace bien el trabajo. Sin embargo, debe tenerse en cuenta que agregar un método move () al prototipo Array se llama "Monkey Patching" y generalmente se considera una mala práctica. stackoverflow.com/questions/5741877/…
Aaron Cicali
20

Si conoce los índices, podría intercambiar fácilmente los elementos, con una función simple como esta:

function swapElement(array, indexA, indexB) {
  var tmp = array[indexA];
  array[indexA] = array[indexB];
  array[indexB] = tmp;
}

swapElement(playlist, 1, 2);
// [{"artist":"Herbie Hancock","title":"Thrust"},
//  {"artist":"Faze-O","title":"Riding High"},
//  {"artist":"Lalo Schifrin","title":"Shifting Gears"}]

Los índices de matriz son solo propiedades del objeto de matriz, por lo que puede intercambiar sus valores.

CMS
fuente
Gracias, @CMS. Si cambio las medias, no quiero reemplazar el orden ... Por ejemplo, si selecciono el tercer objeto en la primera posición, quiero intercambiar 1 como 2 y 2 como 3 como 1
Peri
13

Aquí hay una versión inmutable para aquellos que estén interesados:

function immutableMove(arr, from, to) {
  return arr.reduce((prev, current, idx, self) => {
    if (from === to) {
      prev.push(current);
    }
    if (idx === from) {
      return prev;
    }
    if (from < to) {
      prev.push(current);
    }
    if (idx === to) {
      prev.push(self[from]);
    }
    if (from > to) {
      prev.push(current);
    }
    return prev;
  }, []);
}
chmanie
fuente
Hola, ¿podrías explicarme los beneficios de esta función sobre la respuesta anterior?
Xogno
1
Esta solución no modifica el elemento original, pero devuelve una nueva matriz con la entrada que se mueve.
chmanie
7

Cambie 2 a 1 como primer parámetro en la llamada de empalme al eliminar el elemento:

var tmp = playlist.splice(1, 1);
playlist.splice(2, 0, tmp[0]);
Trevor
fuente
1
debería ser playlist.splice (2,0, tmp [0]); ¿Correcto?
Crisboot
7

Con ES6 puede hacer algo como esto:

const swapPositions = (array, a ,b) => {
  [array[a], array[b]] = [array[b], array[a]]
}

let array = [1,2,3,4,5];
swapPositions(array,0,1);

/// => [2, 1, 3, 4, 5]
ArthurDent
fuente
1
Esto intercambia las posiciones de los dos elementos. La pregunta es para reordenar.
POR
5

Siempre puede usar el método de clasificación, si no sabe dónde está el registro en este momento:

playlist.sort(function (a, b) {
    return a.artist == "Lalo Schifrin" 
               ? 1    // Move it down the list
               : 0;   // Keep it the same
});
Andy E
fuente
What aboutreturn +(a.artist == "Lalo Schifrin")
Funkodebat
2
@Funko podrías hacer eso, si prefieres la brevedad a la verbosidad.
Andy E
2

EDITAR: Por favor, consulte la respuesta de Andy, ya que su respuesta fue la primera y esta es solo una extensión

Sé que esta es una pregunta antigua, pero creo que vale la pena incluirla Array.prototype.sort().

Aquí hay un ejemplo de MDN junto con el enlace

var numbers = [4, 2, 5, 1, 3];
numbers.sort(function(a, b) {
  return a - b;
});
console.log(numbers);

// [1, 2, 3, 4, 5]

Afortunadamente, no solo funciona con números:

arr.sort([compareFunction])

compareFunction

Especifica una función que define el orden de clasificación. Si se omite, la matriz se ordena según el valor del punto de código Unicode de cada carácter, según la conversión de cadena de cada elemento.

Noté que los está ordenando por nombre:

let playlist = [
    {artist:"Herbie Hancock", title:"Thrust"},
    {artist:"Lalo Schifrin", title:"Shifting Gears"},
    {artist:"Faze-O", title:"Riding High"}
];

// sort by name
playlist.sort((a, b) => {
  if(a.artist < b.artist) { return -1; }
  if(a.artist > b.artist) { return  1; }

  // else names must be equal
  return 0;
});

Tenga en cuenta que si se quería ordenarlos por apellido tendría que o bien tienen una clave para ambos first_namey last_name, o hacer un poco de magia de expresiones regulares, que yo no puedo hacer XD

Espero que ayude :)

Jaacko Torus
fuente
Esto debería ser una edición o un comentario sobre esta respuesta .
Jared Smith
@JaredSmith ¡Ups! No vi su respuesta. No tengo suficientes puntos o lo que sea para editar su pregunta, y no creo que toda esta información deba agregarse en un comentario. Entonces, hasta que alguien edite su pregunta, simplemente agregaré que esta es una extensión de la respuesta de Andy E (como debería haber hecho).
Jaacko Torus
Creo que está bien ahora :)
Jared Smith
1

Prueba esto:

playlist = playlist.concat(playlist.splice(1, 1));
JamieJag
fuente
1

Si solo desea mover un elemento desde una posición arbitraria al final de la matriz, esto debería funcionar:

function toEnd(list, position) {
    list.push(list.splice(position, 1));
    return list;
}

Si desea mover varios elementos desde una posición arbitraria hasta el final, puede hacer:

function toEnd(list, from, count) {
    list.push.apply(list, list.splice(from, count));
    return list;
}

Si desea mover varios elementos de una posición arbitraria a una posición arbitraria, intente:

function move(list, from, count, to) {
    var args = [from > to ? to : to - count, 0];
    args.push.apply(args, list.splice(from, count));
    list.splice.apply(list, args);

    return list;
}
Okonomiyaki3000
fuente
0

Como solución mutable simple, puede llamar a splice dos veces seguidas:

playlist.splice(playlist.length - 1, 1, ...playlist.splice(INDEX_TO_MOVE, 1))

Por otro lado, una solución inmutable simple podría usar slice ya que este método devuelve una copia de una sección de la matriz original sin cambiarla:

const copy = [...playlist.slice(0, INDEX_TO_MOVE - 1), ...playlist.slice(INDEX_TO_MOVE), ...playlist.slice(INDEX_TO_MOVE - 1, INDEX_TO_MOVE)]
David
fuente
-2

Reordenar su trabajo de esta manera

 var tmpOrder = playlist[oldIndex];
    playlist.splice(oldIndex, 1);
    playlist.splice(newIndex, 0, tmpOrder);

Espero que esto funcione

Peri
fuente
1
¿Qué agrega esto sobre las respuestas existentes?
Jared Smith