Reordenando matrizes

98

Diga, eu tenho uma matriz parecida com esta:

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

Como posso mover um elemento para outra posição?

Eu quero passar, por exemplo, {artist:"Lalo Schifrin", title:"Shifting Gears"}até o fim.

Tentei usar splice, assim:

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

Mas não funciona.

Wurlitzer
fonte
3
O que "não funciona" significa - gera um erro, não muda nada, muda seu array de uma maneira que você não pretendia? Parece razoável para mim.
Jacob Mattison

Respostas:

220

A sintaxe de Array.spliceé:

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

Onde:

  • índice é a posição na matriz da qual você deseja começar a remover elementos
  • quantos são quantos elementos você deseja remover do índice
  • element1, ..., elementX são elementos que você deseja inserir do índice de posição .

Isso significa que splice()pode ser usado para remover elementos, adicionar elementos ou substituir elementos em um array, dependendo dos argumentos que você passar.

Observe que ele retorna uma matriz dos elementos removidos.

Algo bom e genérico seria:

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

Depois é só usar:

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

Diagrama:

Diagrama de algoritmo

Matt
fonte
17
Essa é uma boa resposta, e o splice () dentro de um splice () faz bem o trabalho. Deve-se notar, entretanto, que adicionar um método move () ao protótipo de Array é chamado de "Monkey Patching" e é normalmente considerado uma prática ruim. stackoverflow.com/questions/5741877/…
Aaron Cicali
20

Se você conhece os índices, pode facilmente trocar os elementos, com uma função simples 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"}]

Os índices de matriz são apenas propriedades do objeto de matriz, portanto, você pode trocar seus valores.

CMS
fonte
Obrigado, @CMS. Se eu trocar as médias não quero substituir a ordem ... Por exemplo, se eu selecionar o 3º objeto para a 1ª posição, quero trocar 1 como 2 e 2 como 3 como 1
Peri
13

Aqui está uma versão imutável para aqueles que estão interessados:

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
fonte
Olá, você poderia me explicar os benefícios dessa função em relação à resposta acima?
Xogno
1
Esta solução não modifica o elemento original, mas retorna uma nova matriz com a entrada sendo movida.
chmanie
7

Altere 2 para 1 como o primeiro parâmetro na chamada de emenda ao remover o elemento:

var tmp = playlist.splice(1, 1);
playlist.splice(2, 0, tmp[0]);
Trevor
fonte
1
deve ser playlist.splice (2,0, tmp [0]); Certo?
Crisboot
7

Com ES6 você pode fazer algo assim:

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
fonte
1
Isso troca as posições dos dois elementos. A pergunta é para reordenar.
EM
5

Você sempre pode usar o método de classificação, se não souber onde o registro está no momento:

playlist.sort(function (a, b) {
    return a.artist == "Lalo Schifrin" 
               ? 1    // Move it down the list
               : 0;   // Keep it the same
});
Andy E
fonte
E sobrereturn +(a.artist == "Lalo Schifrin")
Funkodebat
2
@Funko, você pode fazer isso, se preferir brevidade em vez de verbosidade.
Andy E
2

EDIT: Por favor, verifique a resposta de Andy, pois sua resposta veio primeiro e esta é apenas uma extensão de sua

Sei que é uma pergunta antiga, mas acho que vale a pena incluí-la Array.prototype.sort().

Aqui está um exemplo do MDN junto com o link

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

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

Felizmente, não funciona apenas com números:

arr.sort([compareFunction])

compareFunction

Especifica uma função que define a ordem de classificação. Se omitido, a matriz é classificada de acordo com o valor do ponto de código Unicode de cada caractere, de acordo com a conversão de string de cada elemento.

Percebi que você os está ordenando pelo primeiro nome:

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

note que se você quisesse ordená-los pelo sobrenome, você teria que ter uma chave para ambos first_name& last_nameou fazer alguma mágica regex, o que eu não posso fazer XD

Espero que ajude :)

Jaacko Torus
fonte
Esta deve ser uma edição ou um comentário sobre esta resposta .
Jared Smith
@JaredSmith Oops! Eu não vi sua resposta. Não tenho pontos suficientes ou qualquer outra coisa para editar sua pergunta, e não acho que todas essas informações devam ser adicionadas em um comentário. Então, até que alguém edite sua pergunta, eu simplesmente acrescentarei que esta é uma extensão da resposta de Andy E (como eu deveria ter feito).
Jaacko Torus
Acho que está tudo bem agora :)
Jared Smith
1

Experimente isto:

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

Se você quiser mover apenas um item de uma posição arbitrária para o final da matriz, isso deve funcionar:

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

Se quiser mover vários itens de alguma posição arbitrária para o final, você pode fazer:

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

Se você deseja mover vários itens de uma posição arbitrária para alguma posição arbitrária, tente:

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
fonte
0

Como uma solução mutável simples, você pode chamar splice duas vezes seguidas:

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

Por outro lado, uma solução inmutável simples poderia usar slice, pois esse método retorna uma cópia de uma seção da matriz original sem alterá-la:

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

Reordene seu trabalho desta maneira

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

Eu espero que isso funcione

Peri
fonte
1
O que isso acrescenta às respostas existentes?
Jared Smith