Bob Napkin
Bob Napkin

Reputation: 566

Duplicate-free version of array of objects

I implemented a function that creates a duplicate-free version of an array, but it doesn't work for array of objects. I don't understand and I can't find information how to fix it.

My function:

function uniq(array) {
    var length = array.length;

    if (!length) {
        return;
    }

    var index = 0;
    var result = [];

    while (index < length) {
        var current = array[index];
        if (result.indexOf(current) < 0) {
            result.push(current);
        }
        index++;
    }

    return result;
}

Example:

var my_data = [    
    {
        "first_name":"Bob",
        "last_name":"Napkin"
    },
    {   
        "first_name":"Billy",
        "last_name":"Joe"
    }, 
    {
        "first_name":"Billy",
        "last_name":"Joe",
    }
]

uniq([1, 1, 2, 3]) // => [1, 2, 3]

uniq(my_data) // => [ { "first_name":"Bob", "last_name":"Napkin" }, { "first_name":"Billy", "last_name":"Joe" }, { "first_name":"Billy", "last_name":"Joe" } ]

Do you know someone how to creates a duplicate-free version of array of objects?

Upvotes: 2

Views: 492

Answers (3)

Mike Brant
Mike Brant

Reputation: 71384

Since these objects are simply used for data storage (i.e. they don't have methods or prototype extensions and such applied to them), I might suggest serializing and hashing each object in the array and storing the hashes in an object for determination of uniqueness. Now the question is which hashing function to use. There are a number of md5 and SHA-256 implementations available (search StackOverflow for this). My example will just assume the existence of a hash function called hashFunction().

function uniqArrayObjects(array) {
    // make sure we have an array
    if(Array.isArray(array) === false) {
         console.log('Doh! No array passed.');
         return null;
    }

    var length = array.length;
    // you can return input array if it has 0 or 1 items in it
    // it is already unique
    if (length === 0 || length === 1) {
       return array;
    }

    // object for storing hashes
    var hashTable = {};

    // filter and return the array
    return array.filter(function(obj) {
        var json = JSON.stringify(obj);
        var hash = hashFunction(json);
        if (typeof hashTable[hash] === undefined) {
           // this item doesn't exist in hash table yet
           // add to hash table and return true to add this to filtered result
           hashTable[hash] = 1; // value doesn't matter here
           return true;
        } else {
           return false;
        }
    });
}

Upvotes: 1

6502
6502

Reputation: 114539

A solution if the objects are not huge, the array doesn't have a huge amount of elements and if the objects don't contain reference loops is to use JSON.stringify to decide if two objects are equal...

function uniq(A) {
    var seen = {};
    var result = [];
    A.forEach(function(x) {
        var str = "" + JSON.stringify(x);
        if (!seen[str]) {
            seen[str] = 1;
            result.push(x);
        }
    });
    return result;
}

Upvotes: 1

dudewad
dudewad

Reputation: 13933

indexOf() in javascript does not perform a deep comparison of objects. On top of that, any two objects that are created will never be "equal" to each other. If you do:

var a = {};
var b = {};
a == b; //false
a === b; //false

You need to perform a deep comparison against all values (if that's even what you're looking to do, because there could be other equalities you're looking for). I won't go into how to do a deep comparison because, well, Google.

Upvotes: 1

Related Questions