1

Here is what I need:

var user = {
    'White' : 24,
    'Jack'  : 25,
    'Jone'  : 24,
    ……
}

In this obj, I want to store name and age of a person. And the obj can only store 10 person. If the 11th person is added, the first person should be delete. So I'm thinking of an array, the unshift and pop method:

var user = [
    {'White': 24},
    {'Jack' : 25},
    {'Jone' : 24},
    ……
]
user.unshif({'Bob': 24});
if(user.length>10){user.pop()};

This works fine except one problem. When I want to know White's age, I must use a loop:

for(var i=0; i<user.length; i++){
    ……
}

I don't think it's a good method. is there any array-like object that can meet the needs. And here is what I do:

function arrayObj(){
    var arr = [], obj = {};
    this.pop = function(){
        var o = arr.pop();
        if(o){
            for(var k in o){ delete obj[k]; }
            this.length--;
        }
    };
    this.unshift = function(o){
        arr.unshift(o);
        for(var k in o){ obj[k] = o[k]; }
        this.length++;
    };
    this.length = 0;
    this.get = function(n){
        if(obj[n]!=null && obj[n]!=undefined){
            return obj[n];
        } else {
            return null;
        }
    };
}
var user = new arrayObj();
White Wang
  • 151
  • 1
  • 5
  • so basically you want a Map or Collection to speak in java terms? Just to be clear on what you want. – Tschallacka Apr 10 '15 at 08:43
  • 1
    @White There is no ordered associative data structure in Javascript. You'll have to create your own if you want that. I'd suggest you create an object which keeps associative name-value pairs as you have, but additionally also holds an array in which it stores the keys in order. You will have to update both the object and the array when adding or removing items, but it allows you to do both operations efficiently. – deceze Apr 10 '15 at 08:43
  • @deceze indeed I misread the data structure. If you want the lookup by name to be fast, why not use an object with usernames as keys? That way you can get all the attributes associated with a user via a `users['White']` lookup. – doldt Apr 10 '15 at 08:45
  • @doldt But that alone is not ordered! – deceze Apr 10 '15 at 08:46
  • @deceze thanks for your suggestion, this is what I'm thinking about. I'm looking for a more efficient data structure – White Wang Apr 13 '15 at 04:01
  • @doldt object is convient to map, but it is not ordered. I want to remove the first and add to last like the array does – White Wang Apr 13 '15 at 04:04

4 Answers4

2

Basically what you want is the constant look up speed of a hash table object, but to have the simple ordered structure of an array. Reasonable enough.

The solution I thought of was to use a JavaScript object (hash table basically) to keep track of the indexes at which the person objects are stored on an array. It's not concise but a bit verbose so as to increase readability. Also it doesn't have any error checking but that should be easy enough to add. http://jsfiddle.net/7es2xwqx/

function HashArray(){
    this.indexKeys = {};
    this.storage = [];
}

HashArray.prototype.addUser = function(name, age){
    //if length is 10, storage.shift(), and delete
    //     delete user from indexKeys
    if (this.storage.length === 10) {
       this.storage.shift();
       delete this.indexKeys[name];
    }

    // add user object {name, age} to storage
    // add index of object on storage to indexKeys
    // as {name: indexOnStorage}

    this.indexKeys[name] = this.storage.length;
    this.storage.push({name:name, age:age});
};

HashArray.prototype.getPerson = function(name){
    var indexPersonObjLocated = this.indexKeys[name];
    return this.storage[indexPersonObjLocated];
};
HashArray.prototype.getStorage = function(){
    return this.storage;
};
HashArray.prototype.getKeys = function(){
    return this.indexKeys;
};

var coolObj = new HashArray();
coolObj.addUser("White", 24);
coolObj.addUser("Whate", 25);
coolObj.addUser("Plite", 26);
console.log(coolObj.getUser("White"));
console.log(coolObj.getUser("Whate"));
console.log(coolObj.getUser("Plite"));
Brian Schermerhorn
  • 1,361
  • 1
  • 15
  • 22
1
function obj()
{
  this.__model = [];
}

obj.prototype.add = function(key, value)
{
  this[key] = value;
  this.__model.push({ key: key, value: value });
  if(this.__model.length > 10)
    delete this[this.__model.shift().key];

  console.log(this);
}

http://plnkr.co/edit/dxbiXj5y3e3uiu0Hch7q?p=preview

Jonathan
  • 3,614
  • 3
  • 21
  • 30
  • I'd say you could do away with the `value: value`, but otherwise this is a decent solution. – deceze Apr 10 '15 at 08:55
  • 1
    Using `this.__model` for the queue while leaving read access to `this[key]` but mandating using `.add(key, value)` to modify is sort of inconsistent and hackish. I would do whole API at the same level (methods) and put key-value store as well as queue as members (which would mean the ugly `__` would not be needed). But this works as well, of course. –  Apr 10 '15 at 08:56
0

Maybe you could use the Object.keys function?

var users = {
  "Jack": 24,
  "White": 25
};

var user_history = [
  "Jack",
  "White"
];

function add_user(name, data) {
  var keys = Object.keys(users);
  var first_user;

  if (keys.length > 10) {
    first_user = user_history.shift();
    delete users[first_user];
  }

  users[name] = data;
  user_history.push(name);
}

add_user("Steven");

More info about Object.keys here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys

Icid
  • 1,444
  • 1
  • 12
  • 21
  • 1
    That won't keep the keys in order though. It will delete *a random key*, not the oldest key. – deceze Apr 10 '15 at 08:48
  • Not really sure. IIRC, `Object.keys` maintains insertion order. According to ES5 spec. –  Apr 10 '15 at 08:58
  • @herby It certainly seems that way, but I can't find any solid info on this. – Icid Apr 10 '15 at 09:04
  • @herby Can you link to that spec? MDN says *"in the same order as that provided by a for...in loop"*, which is *"arbitrary"*. – deceze Apr 10 '15 at 09:05
  • @Steven It *may* appear ordered *in practice* simply due to implementation specific realities, but this is nowhere guaranteed and will likely break under any number of circumstances. – deceze Apr 10 '15 at 09:06
  • Don't rely on the order of keys in an Object.keys call. Most browsers will maintain insertion order, but some others will fall back to alphabetical ordering, and older browser versions might use even more exotic approaches. (I know for fact Chrome 40 and PhantomJS 1.9 use different orderings, for example.) – doldt Apr 10 '15 at 09:13
  • I said "IIRC" and I possibly remembered incorrectly; maybe I confuse it with ES6 which seems to actually _specify_ the insertion order in the spec itself. –  Apr 10 '15 at 09:21
0

First, if you know your limit is 10, just use the loop.

First and halfth: constructors should begin with capital letter ;-) You write the code for people that will read it, not for the machine (machine is ok with 0s and 1s).

Second, for these use cases (when n can be higher), to get decent performance you need to use two structures at the same time: queue (implemented for example as array) to be able to add / remove items from it; and key-value store (object in JS, Map in upcoming ES6). To access via key you then use the kvs, to add/remove you use the queue while updating the kvs at the same time.

If you are interested in fast queue implementing, you may look up "Circular queue" or use some lib (eg. https://github.com/herby/queue).

  • 'constructors should begin with capital letter' thanks for the suggestion – White Wang Apr 13 '15 at 04:24
  • 'Object.defineProperty' this function is cool. But in your queue.js, how to add a 'get()' function with no loop – White Wang Apr 13 '15 at 06:02
  • I don't get your question. Maybe you did not get my answer, I do not tend to write in easy-to-understand style. I told you in the answer you need two structures, hash-map-like one and queue-like one. Each for its own purpose. So Queue works out of the box. You should not add anything at all to it. Plus you should have and object acting as a map. That is the one you use for key-lookup. –  Apr 13 '15 at 10:07