0

I have javascript object list and object like this

var student = function (config) 
               { 
                config = config || {}
                this.id = config.id || 1;
                this.Name = config.Name || "Shohel";
                this.Roll = config.Roll || "04115407";
                this.Session = config.Session || "03-04";
                this.Subject = config.Subject || "CSE";
               };
var students = [];
students.push(new student({ id: 2 }));
students.push(new student({ id: 3, Name: "Rana" }));
students.push(new student({ id: 4, Name: "Shipon" }));
students.push(new student({ id: 5, Name: "Pira" }));

Now I want to push another object like this

students.push(new student({ id: 3, Name: "Rana" }));

It is working without any exceptions but I want to check whether this object whose

id is: 3 and Name:"Rana"

already exists in the students list and whether I have too many lists like customers, products, sales etc. then duplicate checking is not possible for every list for me. It will be a hassle for me.

How can I make a generic method for any type of list in javascript that can check for duplicates ?

Shohel
  • 3,562
  • 3
  • 29
  • 66

3 Answers3

1

This is one of the possible ways. May be its not the most efficient one, but it does the job pretty well.

Array.prototype.pushUnique = function (item) {
    var newObj = JSON.stringify(item);
    if (~(this.map(function (obj) { return JSON.stringify(obj); }).indexOf(newObj))) {
        return false;
    } else {
        this.push(item);
        return true;
    }
}

Use pushUnique method to push values to the array, and catch for the exceptions like this

students.pushUnique(new student({id : 2}));
students.pushUnique(new student({id : 3, Name : "Rana"}));
students.pushUnique(new student({id : 2})); // This will throw an error

Note:

This will not work when you use plain JSON object like following

students.pushUnique({id : 2, Name: "Rana"});
students.pushUnique({Name: "Rana", id : 2});

Since the object key sequence is changed and it will result in a different sting when stringified

Edit: (for case mentioned in comments)

If you want to check uniquness for specific keys then you can modify the function like this.

Array.prototype.pushUnique = function (item, uniqueKeys) {
    var newObj = {}, i , keyLen, arr, key;

    if (!uniqueKeys) { uniqueKeys = Object.keys(item); } else if (!(uniqueKeys instanceof Array)) {
        uniqueKeys = [uniqueKeys];
    }

    keyLen = uniqueKeys.length;
    i = keyLen;
    while (i--) { key = uniqueKeys[i]; newObj[key] = item[key]; }
    newObj = JSON.stringify(newObj);

    arr = this.map(function (obj) {
        var obj_temp = {};
        i = keyLen;
        while (i--) { key = uniqueKeys[i]; obj_temp[key] = obj[key]; }
        return JSON.stringify(obj_temp);
    });

    if (~arr.indexOf(newObj)) {
        return false;
    } else {
        this.push(item);
        return true;
    }
}

and use it like

students.pushUnique({Name: "Rana", id : 2}, ["id"]); // Pass keys in an array as second parameter
Salman
  • 8,694
  • 6
  • 35
  • 70
  • You are great. can you give me suggestion how can i return true or false without using throw new Error('Duplicate object'); – Shohel Jun 09 '14 at 05:39
  • hi @Салман, i have same question, can you use indexOf() ?. and how can i catch that have failed? – Shohel Jun 09 '14 at 05:57
  • You mean using indexOf directly on the array? it will check for equality I guess, which will always be false since no two objects will be considered equal. @naota Since he is using a function as object, it will preserve the key sequence for all the objects unlike the case I shown above in note. – Salman Jun 09 '14 at 05:59
  • Hi @Салман, If you push `{id : 2, Name: "Rana"}` into array and stringfy it, the string could be `{Name: "Rana", id : 2}`. Because JSON.stringfy doesn't guarantee the order. The document is here (Description): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify – naota Jun 09 '14 at 06:06
  • @naota Yes, I am aware, that's what I mentioned above in Note. In this case he is using a function to create objects, the keys will always be in order in which they are defined in the constructor. – Salman Jun 09 '14 at 06:12
  • @Салман, Thanks. I understand what you say. Sorry but I'm not sure it's so. What do you think of this? http://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order – naota Jun 09 '14 at 06:22
  • @Салман, Thanks. I want to check duplicate for only property wise, whether it can be id, Name, or Name, Session or Session, Subject. no need to check other property except my providing property. How can i make support to your method?is there any alternative way? – Shohel Jun 09 '14 at 06:32
  • @Md.ShohelRana Checkout the updated code. It should work for specific keys. – Salman Jun 09 '14 at 07:35
  • @Салман, I am facing another problem, i want to check this entry students.pushUnique(new student({ id: 5, Name: "Rana" }), ["id,Name"]), here if 'id' and 'Name' is same then duplicate, other wise not duplicate, but your method check whether id or name exist, this will be '&&' operation not '||' operation. – Shohel Jun 10 '14 at 03:08
  • It is `&&` operation only, you haven't passed the parameters correctly. It should be `["id", "Name"]` instead of `["id,Name"]` – Salman Jun 10 '14 at 05:16
0

You should go to a Factory concept. Try something like this:

var _cache = {};
function recicleObject(type, options){
    // Check if type already registered
    if(!_cache[type])
        _cache[type] = [];

    // Check if ID is already taken
    if(_cache[type][options.id]){
        // Return the already made object
        return _cache[type][options.id];
    }else{
        var obj = new window[type](options);
        _cache[type][options.id] = obj;
        return obj;
    }
}

And then use it like this:

var newStudent = recicleObject('student', {id: ....});

Ivan Seidel
  • 2,216
  • 3
  • 29
  • 43
  • Thanks for your reply. But i want to make common validate method that can check for duplicates. i don't know what are the properties will be check. so you can not fixed options.id...... i can provide checking property as string when will call. – Shohel Jun 09 '14 at 05:34
0

An alternate solution would be to keep another array for the student ids. Before pushing each element check if the student id array has that id, proceed if there is no entry.

Your modified code would be,

var students = [];
var studentIds= [];

var student = function (config) 
             { 
                config = config || {}
                this.id = config.id || 1;
                this.Name = config.Name || "Shohel";
                this.Roll = config.Roll || "04115407";
                this.Session = config.Session || "03-04";
                this.Subject = config.Subject || "CSE";
               };

var pushStudentObj = function(studentObj){

    if(!studentIds.contains(studentObj.id)){
        students.push(studentObj);
    }

}

And to push objects call

pushStudentObj(new student({ id: 2 }));
pushStudentObj(new student({ id: 3, Name: "Rana" }));
pushStudentObj(new student({ id: 4, Name: "Shipon" }));
pushStudentObj(new student({ id: 5, Name: "Pira" }));

This will effectively push only the objects with new Ids!!

Teja
  • 1,166
  • 11
  • 25