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?


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

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.


32

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

var foo,
    bar;
foo = [3,1,2];
bar = foo.slice().sort();

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

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.


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 ).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.