8

I have the following 2D array

var items = [['al','bv','sd'],
             ['al','cc','ab'],
             ['cv','vv','sw'],
             ['al','bv','sd']
            ];

I need a function which will return me a similar array but with distinct values. For example, in the above array, ['al','bv','sd'] happens twice.

I would like the function to return me:

var items = [['al','bv','sd'],
             ['al','cc','ab'],
             ['cv','vv','sw']
            ];
1
  • Does it have to be pure JavaScript or can you use jQuery? Commented Jan 27, 2012 at 15:44

8 Answers 8

6

Quick and dirty solution, assuming the data is small.

On each iteration, convert the row to a string. Use a dictionary to store the string with a value of True, if it is not already in the map. Also, add it to your output array. If it is already in the dictionary, go to the next item.

Example:

var d = {};
var out = [];
for( var i = 0; i < items.length; i++ ) {
    var item = items[i];
    var rep = item.toString();

    if (!d[rep]) {
        d[rep] = true;
        out.push(item);
    }
}

// out has the result
Sign up to request clarification or add additional context in comments.

Comments

4

You have to loop two (or three times):

  1. Loop through all "rows", from beginning to the end
  2. Loop again, through all "rows", from beginning to the end

    • If the lists are equal, ignore it
    • Otherwise,
  3. Loop through all "columns":

    • If the values are not equal, jump to the parent loop.
    • After the loop, remove the element using the .splice method.

Demo: http://jsfiddle.net/EuEHc/

Code:

for (var i=0; i<items.length; i++) {
    var listI = items[i];
    loopJ: for (var j=0; j<items.length; j++) {
        var listJ = items[j];
        if (listI === listJ) continue; //Ignore itself
        for (var k=listJ.length; k>=0; k--) {
            if (listJ[k] !== listI[k]) continue loopJ;
        }
        // At this point, their values are equal.
        items.splice(j, 1);
    }
}

1 Comment

Thank you so much Rob. My nested for loop was giving me some error
4

A simple sort and filter, function would do the trick.

var items = [
  ['al', 'bv', 'sd'],
  ['al', 'cc', 'ab'],
  ['cv', 'vv', 'sw'],
  ['al', 'bv', 'sd']
];

var temp = ''
var unique = items.sort().filter(r => {
  if (r.join("") !== temp) {
    temp = r.join("")
    return true
  }
})

console.log(unique);

Comments

3

An unconventional but easier to code version

var items = [['al','bv','sd'],
             ['al','cc','ab'],
             ['cv','vv','sw'],
             ['al','bv','sd']
            ];

var temp = {};

for ( var i in items ) {
    var serialized = JSON.stringify(items[i]);
    if ( temp[serialized] ) {
        items.splice( i, 1 );
        continue;
    }
    temp[serialized] = true;
} 

Try it here! http://jsfiddle.net/y3ccJ/1/

More conventional option:

var items = [['al','bv','sd'],
             ['al','cc','ab'],
             ['cv','vv','sw'],
             ['al','bv','sd']
            ];

var results = [];

loop: for ( var i in items ) {
    compare: for ( var j in results ) {
        for ( var k in items[i] ) {
            if ( items[i][k] !== results[j][k] ) {
                break compare;
            }
        }
        continue loop;
    }
    results.push( items[i] );
}

http://jsfiddle.net/xhrd6/

Comments

2

If you can use lodash, this is good solution (note that based on your platform, the "require" keyword can differ, this is how to use it in Node.js):

var _ = require('lodash');
var objects = [['a', 'b', 'c'],['a'],['b', 'a', 'c']];
objects.forEach(innerArr => {
  innerArr.sort();
});
console.log(_.uniqWith(objects, _.isEqual));

This would be output

[ [ 'a', 'b', 'c' ], [ 'a' ] ]

If order of elements in array matter to you, i.e. this array [ 'a', 'b', 'c' ] is considered different than this one ['b', 'a', 'c'], all you need is to delete the "sort" part :

var _ = require('lodash');
var objects = [['a', 'b', 'c'],['a'],['b', 'a', 'c'], ['a','b','c']];
console.log(_.uniqWith(objects, _.isEqual));

This would be output :

[ [ 'a', 'b', 'c' ], [ 'a' ], [ 'b', 'a', 'c' ] ]

2 Comments

Thanks for mentionning lodash, I get the feeling it's going to help me a lot :)
@ArnaudBouchot - yes, it will, amazing tool :)
1

You can do something like this :

var result = [];
result.push(items[0]);
for (i = 1; i < items.length; i++){
    var ok;
    for (j = 0; j < i; j++){
        if (result[j].length != items[i].lenght) continue;
        ok = false;
        for (k = 0; k < items[i].length; k++) if (items[i][k] != result[j][k]) ok = true;
        if (ok == false) break; 
    }
    if (ok) result.push(items[i]);
}
return result;

Comments

1
function arrays_equal(a,b) { return !!a && !!b && !(a<b || b<a); }

Array.prototype.unique = function() {
    var a = [];
    for (var i = 0, l = this.length; i<l; i++) {
        for (var j = i + 1; j < l; j++) if (arrays_equal(this[i], this[j])) j = ++i;
        a.push(this[i]);
    }
    return a;
};

var ret = items.unique();

The demo.

Comments

0

Since this sounds like some sort of school assignment I will provide ideas not code. You should think about how a human looks through that 2D array and determines whether or not one of the arrays is unique or not. One has to look at each other row, for each row to determine if it is unique. Sounds like nested for loop to me ....

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.