2014-06-05 17 views
5

Tutta la documentazione per la creazione di sub-array che ho visto parla di slice, che crea una copia dell'array. Mi chiedo se sia possibile creare una porzione di una matrice senza copiare, in modo che la modifica della sezione modifichi la matrice originale. Per esempio:Subarray JavaScript senza copiare?

var foo = [1, 2, 3, 4, 5]; 
var bar = foo.subarray(2, 4); 
console.log(bar); // [2, 3, 4] 
bar[0] = 'hello, world'; 
console.log(bar); // ['hello, world', 3, 4] 
console.log(foo); // [1, 'hello, world', 3, 4, 5] 

risposta

0

Non credo, questo è possibile, perché intero è un semplice tipo di dati, se si rap in un oggetto, sarebbe possibile credo.

Ecco una demo di lavoro:

function co(value) 
{ 
    var obj = new Object(); 
    obj.data = value; 
    obj.setValue = function(value) 
    { 
     this.data = value; 
    } 
    return obj; 
} 

var foo = [co(1), co(2), co(3), co(4), co(5)]; 
var bar = foo.slice(2, 4); 
console.log(bar); 
console.log(foo); 
bar[0].setValue('hello, world'); 
console.log(bar); 
console.log(foo); 

http://jsfiddle.net/VGLdP/

+0

Sì, usare 'slice' non funziona per quello che voglio. L'idea è di ottenere una nuova vista nello * stesso * array (dove l'unica differenza è l'indice iniziale), non crearne uno nuovo. –

+0

In realtà è possibile, usando setter e getter. Non pratico, ma possibile. – Gio

4

Questo codice simula riferimenti (puntatori), come in altre lingue:

Array.prototype.subarray = function(i, j){ 
    var self = this, arr = []; 
    for(var n = 0;i <= j; i++, n++){ 
     (function(i){ 
      Object.defineProperty(arr, n, {  //Array is an Object 
       get: function(){ 
        return self[i]; 
       }, 
       set: function(value){ 
        self[i] = value; 
        return value; 
       } 
      }); 
     })(i); 
    } 
    return arr; 
} 


//This is the exact code you have in your question 
var foo = [1, 2, 3, 4, 5]; 
var bar = foo.subarray(2, 4); 
console.log(bar);     // [3, 4, 5] 
bar[0] = 'hello, world';    // some magic happens here 
console.log(bar);     // ['hello, world', 4, 5] 
console.log(foo);     // [1, 2, 'hello, world', 4, 5] 

Demo: http://jsfiddle.net/DerekL/y7z9T/

subarray fa non creat e un nuovo array copiando l'array originale; crea una matrice vuota con custom getters. Una cosa da tenere a mente è che i valori nel nuovo array sono collegati all'indice dell'array originale, invece della sua posizione di memoria.

  index 
    0 1 2 3 4 
     ┌────────────┐ 
┌───┬───┬┤───┬───┬───┐│ 
│ 1 │ 2 ││ 3 │ 4 │ 5 ││ 
└───┴───┴┤───┴───┴───┘│ 
     └────────────┘ 
├──── Whole Array ────┤ 
     ├─ SubArray ─┤ 

Il "sub array" fornisce una "finestra" per l'array originale. Puoi modificare e ottenere i valori di contenimento in entrambi gli array come faresti normalmente. Cambiare uno di essi avrà effetto su entrambi. Tuttavia, se provi a inserire nuovi elementi nel "sub array", le cose brutte succedono, quindi non farlo.

Per ulteriori informazioni su defineProperty per favore visit MDN.

+0

Questo richiede O (n) tempo, ma possiamo farlo in O (1). –

5

Purtroppo, @ risposta di Derek prende O(n) per creare un sottoarray di lunghezza n, mentre siamo in grado di farlo in O(1) se accediamo valori con subarray.get(i) invece di subarry[i]:

function make_subarray (array, from, to) { 
    return { 
     get: function (i) { 
      return array[i+from] 
     }, 
     length: to - from 
    } 
} 

si può usare questa come:

for (var i=0; i<subarray.length; i++) { 
    subarray.get(i) 
} 

Oppure è possibile aggiungere una funzione map() alla definizione subarray:

function make_subarray (array, from, to) { 
    return { 
     ... 
     map: function (f) { 
     for (var i=0; i<this.length; i++) 
      f(this.get(i)) 
     } 
     ... 
    } 
} 

Ogni chiamata a Object.defineProperty(...{get: ...}) nella risposta di Derek è lenta nei browser moderni, quindi è bene evitare di eseguirne molti.

+0

Credo che la sua intenzione fosse di riutilizzare la sintassi nativa durante la simulazione di un sottoarray che fa riferimento allo stesso pezzo di memoria della matrice originale. Concordo sul fatto che potrebbe essere asintoticamente più lento durante la creazione del "sottoarray", ma dubito che nella pratica ci saranno differenze di prestazioni apprezzabili a meno che non si gestisca un enorme insieme di dati (in questo caso, scegliere una struttura dati migliore!). –

+1

Se il motivo per evitare la copia è che l'array è lungo, farlo in O (1) è l'intero punto, ovviamente. –

+0

Non sono sicuro, ma la modifica di ciascun accesso di array in una chiamata di funzione potrebbe avere problemi di prestazioni. – CMCDragonkai

Problemi correlati