2

I am wondering how I can check if a duplicate pair of values in an array exist as part of a larger array in javascript. You can see there is a duplicate pair of [1,2] - so the function should just return true. i.e

var arr = [[1,2], [3,4], [5,6], [7,8], [9,10], [11,12], [13,14], [1,2]]

I have tried using this logic which gives me a clean array and a "true"

var unique = [];
var done = []; var dup = false;
for(var x = 0; x < arr.length; x++) {
    var myStr = arr[x].toString();

    if(done.indexOf(myStr) != -1) {
        // val already exist, ignore
        dup = true;
        continue;
    }

    done.push(myStr);
    unique.push(arr[x]);
}

But I was wondering if there is something more elegant using Underscore ?

3 Answers 3

5

The shortest way would be to use _.uniq and JSON.stringify:

function unique(arr) {
    return _.uniq(arr, JSON.stringify).length === arr.length;
}

But that doesn't short-circuit, so it's somewhat slow compared to the other ways you could do it. Tomalak's second function should be faster.

Sign up to request clarification or add additional context in comments.

15 Comments

JSON.stringify is a lot nicer than .toString() or .join(). +1 PS: Hah, we implemented the same pure JS solution... :) I'd just be careful with the use of in. hasOwnProperty() returns false for the string "length", in would return true.
The second solution doesn't actually work if an array contains strings that look like joined arrays like "1,2" etc. Remember, object keys are always strings! stringify is much better as it carries type and uses it for comparisons.
@thg435: Well, if I were to fix it, then you'd basically get Tomalak's answer ;)
@Blender: he's making the same mistake: containsDuplicates([[1,2], "1,2"]) returns true.
@Andy: Yep. If the array without duplicates has the same number of elements as the array with duplicates, then no duplicates were ever there.
|
2

Well, uniq seems like a good fit

function containsDuplicates(arr) {
  return arr.length !== _.uniq(arr, function (item) { return item.toString(); }).length;
}

You should use Blender's version of this function. It's shorter and safer.


BTW, your code should look more like this:

function containsDuplicates(arr) {
    var index = {}, i, str;

    for(i = 0; i < arr.length; i++) {
        // you could use arr[i].toString() here, but JSON.stringify()
        // is a lot safer because it cannot create ambiguous output.
        str = JSON.stringify(arr[i]);
        if (index.hasOwnProperty(str)) {
            return true;
        } else {
            index[str] = true;
        }
    }

    return false;
}

Note that this is probably more efficient than the underscore one-liner.

8 Comments

@WillemD'haeseleer I'm pretty sure it works. How did you test it?
in my browser, seems like Blender fixed it for you now
@Willem Darn copy/paste mistakes. Yes, that was it.
@Tomalak - thanks for the response. Is there a way to check whether the latest pair pushed to the array is a duplicate ? Not just whether "any duplicate" exists ? i.e. like containsDuplicates(arr, newPair) - which is like containsDuplicates(arr, [5,6])
@Andy If you ask me like this... yes, there is a way to do this. :)
|
2

Although stringify is the answer most of the time, it still has its issues, for example {"x":1,"y":2} and {"y":2,"x":1} are considered different. If you need a 100% accurate comparison, there's no other way as to store already processed objects and deep compare them (luckily, underscore provides an utility for this).

uniq2 = function(xs) {
    return _.reduce(xs, function(result, x) {
        if(!_.any(result, _.partial(_.isEqual, x)))
            result.push(x);
        return result;
    }, []);
}

Test:

var arr = [[1,2], [3,4], "1,2", "[1,2]", [1,2], {x:1,y:2}, {y:2,x:1}]
console.log(uniq2(arr))
// [[1,2],[3,4],"1,2","[1,2]",{"x":1,"y":2}]

This is going to be quadratic in the worst case, but there's no other way.

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.