javascript - Datatype som kombinerer egenskaper av array og ordbok
I prosjektet mitt har jeg en samling objekter (klasseinstanser) som jeg trenger å få tilgang til ved nøkkel, men også sortere og få tilgang til i en gitt rekkefølge. Hvordan bør jeg lagre disse objektene?
Jeg kunne ha både Array og Dictionary og manuelt holde dem synkronisert, men dette er suboptimalt (for eksempel når du vil slette et objekt må du først lokalisere det i Arrayet).
//dictionary properties
objectsDictionary[object.id] = object;
//array properties
objectsArray.sort(function)
Finnes det en datastruktur som kombinerer egenskapene til både Array og Dictionary? Kan en slik struktur moduleres uten å måtte traversere arrayet internt?
Språket jeg jobber i er TypeScript, men svaret kan være mer generelt.
Svar #1
Du kan implementere dette selv ved å bruke en konstruktør som dette. Merk at flertallet av metodene må defineres på instansen fordi de bruker referanser som ikke deles.
/* OADictionary
* value getItemAt , int index
* value getItem , str key
* void addItem , str key, value [, int index]
* void removeItemAt , int index
* void removeItem , str key
* void sort , function comparator(key_a, key_b, val_a, val_b)
*/
function OADictionary() {
var keys = [],
obj = {};
this.getItemAt = function (index) {
return obj[keys[index]];
};
this.getItem = function (key) {
return obj[key];
};
this.addItem = function (key, val, index) {
if (obj[key]) throw new Error('key already exists: ' + key);
obj[key] = val;
if (index || index === 0)
keys.splice(index, 0, key);
else
keys.push(key);
};
this.removeItemAt = function (index) {
delete obj[keys[index]];
keys.splice(index, 1);
};
this.removeItem = function (key) {
delete obj[key];
keys.splice(keys.indexOf(key), 1);
};
this.sort = function (comparator) {
var mComparator = function (key_a, key_b) {
return comparator(key_a, key_b, obj[key_a], obj[key_b]);
};
if (comparator)
keys.sort(mComparator);
else
keys.sort();
};
}
Nå kan du lage dine ordnede nøkkel-verdi-par
var d = new OADictionary();
d.addItem('foo', 'bar');
d.addItem('fizz', 'buzz');
d.getItem('fizz'); // "buzz"
d.getItemAt(0); // "bar"
d.sort();
d.getItemAt(0); // "buzz"
Svar #2
Generelt i JavaScript kan du ikke kombinere vilkårlig indeksering med noe annet på det samme objektet og få forutsigbare resultater. For eksempel:
var arrayAndDictionary = /*... something ...*/;
// Accidently malicious user data
var objects = [{ id: 'sort' }, {id: 'length'}, {id: 'forEach' }];
objects.forEach(object => {
arrayAndDictionary[object.id] = object;
});
objects.sort(); // Crash.
Virkelig, du vil ikke engang bruke et ID med mindre du er 100 % i kontroll over disse ID-ene og er veldig forsiktig. Du kan bli brent av Lille Bobby Proto:
// Collection of users on our website
var myObjects = {};
// New user named __proto__ signs up
myObjects['__proto__'] = { 'userId': 'bobby' }
// Is there a user named 'userId' ?
alert(myObjects['userId']); // "bobby", not undefined
