Skip to content

Instantly share code, notes, and snippets.

@kaareal
Created May 1, 2011 09:57
Show Gist options
  • Save kaareal/950383 to your computer and use it in GitHub Desktop.
Save kaareal/950383 to your computer and use it in GitHub Desktop.
var index = 0;
results = [],
prevLen;
while(true) {
r.albums[index] && results.push(r.albums[index]);
r.tracks[index] && results.push(r.tracks[index]);
r.artists[index] && results.push(r.artists[index]);
if(prevLen == results.length || results.length >= 9) {
break;
}
prevLen = results.length;
index++;
}
results = results.splice(0,9)
@datafatmunger
Copy link

I like this:
r.albums[index] && results.push(r.albums[index]);

However a while(true) broken with a conditional is about WORST practice, how about this:

for(var index = 0; results.length < (r.albums.length + r.tracks.length + r.artists.length); index++) {
r.albums[index] && results.push(r.albums[index]);
r.tracks[index] && results.push(r.tracks[index]);
r.artists[index] && results.push(r.artists[index]);
}

results = results.splice(0,9);

@kaareal
Copy link
Author

kaareal commented May 1, 2011

yeah i like yours better,

var max = results.length + r.tracks.length + r.artists.lenght;
for(var i = 0; i < max || results.length <= 9; i++) {
r.albums[index] && results.push(r.albums[index]);
r.tracks[index] && results.push(r.tracks[index]);
r.artists[index] && results.push(r.artists[index]);
}
results = results.splice(0,9)

@zenmumbler
Copy link

The "r.albums[index]" test will fail if any of the values encountered equates to false (0, "", false, null, undefined)
Both revised version will also run for much too long, generating an enormous result array if the input is very large. The (|| should be && in the for test)

My stab at it, tested in a browser with various values, empty arrays, etc, seems to work.
To test, just replace the ... placeholders with array initializers.

var src_a = [[...], [...], [...]]; // source arrays, each array can hold 0..∞ elements.
var out   = []; // results
var rmax  = Math.min(9, src_a[0].length + src_a[1].length + src_a[2].length);

for(var rx = 0; out.length < rmax; ++rx) {
    var src = src_a[rx % 3];     // current source array, round-robin
    var ex = Math.floor(rx / 3); // element index, js upconverts to float, so need to simulate (int) cast
    if(src.length > ex) out.push(src[ex]);
}

Note that the test of the loop doesn't test rx, but the actual length of the results so far.

@kaareal
Copy link
Author

kaareal commented May 1, 2011

I think we got a winner.

@datafatmunger
Copy link

I do love Arthur's code. It's very nice. That said, I'm sort of okay with the "r.albums[index]" test failing, since we are dealing with strings here (albums, artists, tracks), I don't want those falsy values in my array anyway. Kaare's second iteration for(var i = 0; i < max || results.length <= 9; i++) will keep results from getting too large or too slow.

@datafatmunger
Copy link

Sorry, should be: for(var i = 0; i < max && results.length <= 9; i++). Arthur was correct.

@zenmumbler
Copy link

just for shits n giggles, the C++03 version. Inline initialization of variable size arrays is a bit kludgey, a shortfall which is remedied in C++0x, whose new move semantics would also make the vector copy on return a move operation, i.e. "free." Boost also makes things more concise but I went for the basic version here.
Tested in Xcode 4.

using std::vector;
vector<int> merge3() {
    int src_a[3][4] = { { 1,2 }, { 3,4,5 }, { 6,7,8,9 } };
    vector<int> const va[3] = { vector<int>(src_a[0], src_a[0]+2), vector<int>(src_a[1], src_a[1]+3), vector<int>(src_a[2], src_a[2]+4) };
    vector<int> results;
    int rmax = std::min(9, va[0].size() + va[1].size() + va[2].size());

    for(int rx = 0; results.size() < rmax; ++rx) {
        vector<int> const &vsrc = va[rx % 3];
        int ex = rx / 3;
        if(vsrc.size() > ex) results.push_back(vsrc[ex]);
    }
    return results;
}

@zenmumbler
Copy link

C++0x version, not completely sure about correctness, but just to show use of initializer lists, auto typing and move semantics, renamed vars for better comparison with js version, and really, save for a few parentheses and types it's the same. I'm likely the only one of us who cares about this ;)

using std::vector;
vector<int>&& merge3() {
    vector<int> const src_a[3] = { { 1,2 }, { 3,4,5 }, { 6,7,8,9 } };
    vector<int> out;
    int rmax = std::min(9, src_a[0].size() + src_a[1].size() + src_a[2].size());

    for(int rx = 0; out.size() < rmax; ++rx) {
        auto src = src_a[rx % 3];
        int ex = rx / 3;
        if(src.size() > ex) out.push_back(src[ex]);
    }
    return results;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment