6

I want to compare many arrays and combine any that are identical:

A = [1,2,3];
B = [1,2,3];
C = [1,2,3];

D = [10,11,12];
E = [10,11,12];
F = [10,11,12];

G = [13,14];
H = [13,14];

If there are identical arrays then I'd like to create new arrays out of the identical ones:

I = [1,2,3];
J = [10,11,12];
K = [13,14];

Would I need to iterate through each element in one array against ALL of the elements in the other arrays?

for (var i in A) {
    for (var j in B) {
        if (A[i] == J[j]) {
            // create new arrays
        }
    }
}

etc...

Then, create new arrays out of the matches? Sounds like a lot of overhead.

What's the best way to accomplish this?

Thanks!

3
  • for-in iterates over object keys. It is not a for-each loop and you should not use it on arrays. Commented Oct 8, 2011 at 3:11
  • @missingno comments are great but try to explain WHY something should not be used or provide a link please. Thanks. Commented Oct 11, 2011 at 4:07
  • I should have been more explicit. Arrays have other properties in addition to the index ones (the ones you really care about) and for-in can iterate over them as well (unless your browser goes all the way to protect you from that). This is specially dangerous if you decide to one day use a library that alters Array.prototype, like MooTools or Prototype, and suddenly lots of spurious stuff starts appearing on your loops. To iterate oven an array you should either use a plain for-loop or one of the iterations methods like .forEach (if that is supported by your browser/libraries) Commented Oct 11, 2011 at 12:43

6 Answers 6

6

If you're just trying to finish up with the unique arrays, I would use a hash approach:

var myArrays = [A,B,C,D,E,F,G],
    uniques = [],
    hashes = {};

for (var i=0; i < myArrays.length; i++) {
    var hash = JSON.stringify(myArrays[i]); // or .toString(), or whatever
    if (!(hash in hashes)) {
        hashes[hash] = true;
        uniques.push(myArrays[i]);
    }
}
// uniques now holds all unique arrays
Sign up to request clarification or add additional context in comments.

5 Comments

Still have some issues working with this except for one scenario. Crazy, I know but that's how it is. Can you provide a jsFiddle example that works well?
Here you go: jsfiddle.net/nrabinowitz/L4Ekx/1 . I had a typo in my for loop - var i; should have been var i=0;. Corrected above.
After various tests, I just have to say that this works extremely well! To make JSON.stringify work with legacy browsers all I needed to add was Douglas Crockford's JSON-js mini-lib. I called the json2.js file and all was golden, especially in IE 6/7: github.com/douglascrockford/JSON-js
If I could add more points for your answer I would! Thank you :)
Glad this works for you! JSON.stringify is probably the best available hash function here, but you might be able to get away with a simple .toString() if you know your arrays will only hold numbers or strings.
2

Depending on your definition of identical, you could just convert to string and compare those.

if (A.toString() == B.toString()) { //combine }

Comments

1

If you are just comparing arrays of primitives- numbers or strings, say- you can compare their string representation.

function simpleArrayMatch(A,B){
    return String{A)===String(B);
}

2 Comments

I'm curious about this function. Can you flush it out a bit more so I can see it working context?
No jsFiddle sample? Works well for one set of arrays but what about multiple?
1

Well... I would do it this way

function combine(arr1, arr2)
{
    if(arr1.join(',') === arr2.join(','))
        return arr1;
}

or for many arrays

function combine(arrList)
{
    var pass = true;
    var compareArray = arrList[0];
    for(var i in arrList)
        pass = pass && (arrList[i].join(',') === compareArray.join(','));
    if(pass)
        return compareArray;
}

arr = combine([[1,2,3],[1,2,3],[1,2,3]]); // results in [1,2,3]

6 Comments

@nrabinowitz I don't see how it's any different than any of the other approaches listed. Even in yours it loops as many times as there are arrays. The only difference is yours stores them in an object. Yours also has the potential to make multiple comparisons (the hash in hashes part) making it touch arrays more than the number of arrays that exist (e.g. for 5 arrays it might make 8 comparisons). Mine in that situation would only make 5 comparisons or even 4 if I optimized it.
I'm only comparing the hashes, not the arrays. My version is O(n) - for 5 arrays, it makes 5 hash-in-object lookups. Maybe I'm missing something about your version - I'm just not seeing how your approach takes a list of arrays and results in a list of unique arrays, which I think is what the OP wants.
I don't think this solution is correct; all it does is check to see if the first array is equal to all of the others, and if it is, it returns that first array.
@Peter that's what the OP requested. The goal was to merge identical arrays. You can compare them as strings and if they're identical there's no real point in merging. You can just return the first one.
@Joseph - yes, but if you wanted all of the unique arrays (which the OP does, I think), you'd need to run this with every array in the sequence, comparing against every other array.
|
1

Suppose all you have inside each array are numbers or texts only, so this maybe a feasible approach without looping through any array:

(See fiddle here)

The code :

A = [1,2,3];
B = [1,2,3];
C = [1,2,3];

D = [10,11,12];
E = [10,11,12];
F = [10,11,12];

G = [13,14];
H = [13,14];

function compareArr(arrList){
    var S = '@' + arrList.join('@');
    var re = /(@[^@]+)(@.*)?(\1)(@|$)/gi
    var afterReplace=''; var i=0;
    while(afterReplace!=S && i<100){
        afterReplace=S;
        S = S.replace( re, "$1$2$4" )
        i++
    }

    return S.substr(1,S.length-1).replace(/@/g,'<br>')
}

$('html').append( compareArr([A,B,C,D,E,F,G,H]) )

Strategy is to join all the array into a string with "@" as the separator. Then use regex to replace all the duplicated piece inside the string, finally split the string then you have the list unique arrays.

The reason to use a while loop in my code is just because I can't write a better regex pattern to remove duplicated piece at once. Looking for a better regex?

Comments

0

I believe so, but at the very least you can use a compare array function to make it easier, even if it's just as slow:

function compareArrays(arr1,arr2)
{
    if (arr1.length != arr2.length) return false;
    for (var i = 0; i < arr2.length; i++) 
    {
        if (arr1[i].compareArrays) 
        { //likely nested arr2ay
            if (!arr1[i].compareArrays(arr2[i])) return false;
            else continue;
        }
        if (arr1[i] != arr2[i]) return false;
    }
    return true;
}

Then, you just need to use this function as you loop through the arrays.

1 Comment

I want to note that I got this function elsewhere, possibly on Stackoverflow, but I've long since forgotten where.

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.