Como você pode classificar uma matriz sem alterar a matriz original?

230

Vamos supor que eu queria uma função de classificação que retorne uma cópia classificada da matriz inserida. Eu tentei ingenuamente isso

function sort(arr) {
  return arr.sort();
}

e eu testei com isso, o que mostra que meu sortmétodo está alterando a matriz.

var a = [2,3,7,5,3,7,1,3,4];
sort(a);
alert(a);  //alerts "1,2,3,3,3,4,5,7,7"

Eu também tentei essa abordagem

function sort(arr) {
  return Array.prototype.sort(arr);
}

mas não funciona.

Existe uma maneira simples de contornar isso, preferencialmente uma maneira que não exija a rolagem manual do meu próprio algoritmo de classificação ou a cópia de todos os elementos da matriz para um novo?

Peter Olson
fonte
1
crie uma cópia profunda da matriz e classifique-a.
evanmcdonnal
1
@evanmcdonnal Uma cópia superficial pode ser boa o suficiente se tudo o que se deseja é uma reordenação e não uma duplicata de todos os itens da matriz.
Kekoa
.sortrequer que o thisvalor seja a matriz, portanto, para o último trecho funcionar, você faria .sort.call(arr)(embora isso não resolva o seu problema).
Pimvdb
@Kekoa Sim, esse é um bom argumento. Não há necessidade de consumir mais memória se você quiser alterar apenas a ordem dos elementos e não os próprios elementos.
evanmcdonnal
O método do zzzzBov está funcionando como um encanto! stackoverflow.com/a/9592774/7011860
Samet M.

Respostas:

222

Basta copiar a matriz. Há muitas maneiras de fazer isso:

function sort(arr) {
  return arr.concat().sort();
}

// Or:
return Array.prototype.slice.call(arr).sort(); // For array-like objects
Rob W
fonte
2
Isso fará uma cópia profunda, ou seja, objetos e matrizes aninhados também serão copiados?
31812 Peter Olson
2
Existe alguma vantagem em usar concatover say slice(0)ou todos eles são praticamente iguais?
JaredPar
3
@ PeterOlson Não, é uma cópia superficial. Se você realmente deseja uma cópia detalhada, use o recurso de pesquisa no Stack Overflow para encontrar excelentes respostas existentes para isso.
22712 Rob Rob W
11
Slice agora é relatado como notavelmente mais rápido
Zander Brown
3
por que ao Array.prototype.slice.call(arr).sort();invés de arr.slice().sort();?
Olivier Boissé 25/10/19
61

Tente o seguinte

function sortCopy(arr) { 
  return arr.slice(0).sort();
}

A slice(0)expressão cria uma cópia da matriz iniciando no elemento 0.

JaredPar
fonte
32

Você pode usar fatia sem argumentos para copiar uma matriz:

var foo,
    bar;
foo = [3,1,2];
bar = foo.slice().sort();
zzzzBov
fonte
Esta resposta é incrível! Estou surpreso que o JavaScript permita uma mutação nesse nível. Parece errado. Obrigado novamente.
12

Você também pode fazer isso

d = [20, 30, 10]
e = Array.from(d)
e.sort()

Dessa forma, d não será alterado.

function sorted(arr) {
  temp = Array.from(arr)
  return temp.sort()
}

//Use it like this
x = [20, 10, 100]
console.log(sorted(x))
Aditya Agarwal
fonte
Esta resposta é agradável
Leasye 18/02
1

Qualquer pessoa que queira fazer uma cópia profunda (por exemplo, se sua matriz contiver objetos) pode usar:

let arrCopy = JSON.parse(JSON.stringify(arr))

Então você pode classificar arrCopysem alterar arr.

arrCopy.sort((obj1, obj2) => obj1.id > obj2.id)

Observe: isso pode ser lento para matrizes muito grandes.

Hamada
fonte
Isso funcionará com em -vez de >no seu segundo exemplo.
pootzko
0

Eu uso Object.assign () para a maioria das minhas cópias:

var copyArray = Object.assign([], originalArray).sort();

No entanto, depois de examinar os comentários do OP, pesquisei um pouco de cópia profunda e constatamos que o Object.assign não apenas executa uma cópia superficial, mas também seleciona apenas propriedades enumeráveis ​​e próprias (conforme respondido neste post ).

Sun Lee
fonte