2016-06-27 21 views
13

Come può la seguente operazione avvenire senza mutare la matrice:Sostituire elemento nella posizione specifica in un array senza mutare lo

let array = ['item1']; 
console.log(array); // ['item1'] 
array[2] = 'item2'; // array is mutated 
console.log(array); // ['item1', undefined, 'item2'] 

Nel codice precedente, array variabile è mutato. Come posso eseguire la stessa operazione senza modificare l'array?

+0

Se si desidera qualcosa ** ** veloce https://stackoverflow.com/a/47943825/1480391,;) –

risposta

26

È possibile utilizzare Object.assign:

Object.assign([], array, {2: newItem}); 
+1

@DanPrince Non sono sicuro di come queste strutture di condivisione applicazione. Ma slice copia l'array completo in modo che anche case sia O (n). – Oriol

+0

Qualsiasi documentazione su 'Object.assign'? –

+0

Detto questo, copiare un array con 'slice' potrebbe essere più veloce perché prima viene copiato' length', quindi la preallocazione è possibile. 'Object.assign (array.slice(), {2: newItem});' è un'altra possibilità. – Oriol

5

Si può semplicemente impostare un una nuova matrice in quanto tale:

const newItemArray = array.slice(); 

E poi impostare il valore per l'indice che si desidera avere un valore per.

newItemArray[position] = newItem 

e restituirlo. I valori sotto gli indici intermedi avranno undefined.

O l'alternativa sarebbe ovviamente:

Object.assign([], array, {<position_here>: newItem}); 
1

var list1 = ['a','b','c']; 
 
var list2 = list1.slice(); 
 
list2.splice(2, 0, "beta", "gamma"); 
 
console.log(list1); 
 
console.log(list2);

E 'questo quello che vuoi?

4

Beh, tecnicamente questo non sarebbe in sostituzione di in quanto non c'è un articolo nell'indice che si sta modificando.

Guarda come viene gestito in Clojure, un linguaggio costruito attorno a implementazioni canoniche per strutture di dati immutabili.

(assoc [1] 2 3) 
;; IndexOutOfBoundsException 

Non solo non riesce, ma si blocca anche. Queste strutture dati sono progettate per essere il più robuste possibile e quando si incontrano questi tipi di errori, generalmente non è perché hai scoperto un caso limite, ma più probabilmente stai usando la struttura dati sbagliata.

Se si finisce con gli array sparsi, prendere in considerazione la modellazione con oggetti o mappe.

let items = { 0: 1 }; 
{ ...items, 2: 3 }; 
// => { 0: 1, 2: 3 } 

let items = new Map([ [0, 1] ]); 
items(2, 3); 
// => Map {0 => 1, 2 => 3} 

Tuttavia, Map è una struttura dati fondamentalmente mutevole, così avresti bisogno di scambiare questo per una variante immutabile, con una libreria come Immutable.js o Mori.

let items = Immutable.Map([ [0, 2] ]); 
items.set(2, 3); 
// => Immutable.Map {0 => 1, 2 => 3} 

let items = mori.hashMap(); 
mori.assoc(items, 2, 3); 
// => mori.hashMap {0 => 1, 2 => 3} 

Naturalmente, ci potrebbe essere un buon motivo per voler usare gli array di JavaScript, quindi ecco una soluzione per buona misura.

function set(arr, index, val) { 
    if(index < arr.length) { 
    return [ 
     ...arr.slice(0, position), 
     val, 
     ...arr.slice(position + 1) 
    ]; 
    } else { 
    return [ 
     ...arr, 
     ...Array(index - arr.length), 
     val 
    ]; 
    } 
} 
0

Ecco come mi piacerebbe farlo:

function update(array, newItem, atIndex) { 
    return array.map((item, index) => index === atIndex ? newItem : item); 
} 

In generale, il funzionamento Array diffusa produce pochi array temporanei per voi, ma map no, quindi può essere più veloce.È inoltre possibile consultare this discussion come riferimento

+0

Bello, ma la discussione di Redux riguarda la rimozione di un elemento, penso il modo più veloce per sostituire un elemento è https://stackoverflow.com/a/47943825/1480391;) –

Problemi correlati