reduce array of arrays into on array in collated order












6















I'm trying to use reduce() combine a set of arrays in a "collated" order so items with similar indexes are together. For example:



input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]

output = [ 'first','1','uno','one','second','2','dos','two','third','3','three','4' ]


It doesn't matter what order the items with similar index go as long as they are together, so a result of 'one','uno','1'... is a good as what's above. I would like to do it just using immutable variables if possible.



I have a way that works:



    const output = input.reduce((accumulator, currentArray, arrayIndex)=>{
currentArray.forEach((item,itemIndex)=>{
const newIndex = itemIndex*(arrayIndex+1);
accumulator.splice(newIndex<accumulator.length?newIndex:accumulator.length,0,item);
})
return accumulator;
})


But it's not very pretty and I don't like it, especially because of the way it mutates the accumulator in the forEach method. I feel there must be a more elegant method.



I can't believe no one has asked this before but I've tried a bunch of different queries and can't find it, so kindly tell me if it's there and I missed it. Is there a better way?



To clarify per question in comments, I would like to be able to do this without mutating any variables or arrays as I'm doing with the accumulator.splice and to only use functional methods such as .map, or .reduce not a mutating loop like a .forEach.










share|improve this question

























  • "Is there a better way?" What do you mean by "better"? "I don't like it" is not an objective coding problem. What is the requirement?

    – guest271314
    4 hours ago













  • Well for one thing I'd like to do it without mutating any variables, or introducing a .forEach loop which isn't really functional. And I think it can be done much more concisely as well. If I could zip a set of arrays together like in Python then reduce(concat) them together that way would work too.

    – jimboweb
    4 hours ago











  • I think I pretty clearly said I'd like the result to not mutate any arrays or variables, as I am doing with the accumulator.splice. That is an objective requirement.

    – jimboweb
    4 hours ago











  • Does the requirement include a restriction on using JSON.parse(JSON.stringify(input)) to avoid mutating the original array?

    – guest271314
    3 hours ago













  • Wow, lots of great answers, thanks. I'm a little torn on which one to accept as a solution, so I have to try them out. I'll choose a solution in a day or so. but I voted you all up. Thanks again.

    – jimboweb
    38 mins ago
















6















I'm trying to use reduce() combine a set of arrays in a "collated" order so items with similar indexes are together. For example:



input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]

output = [ 'first','1','uno','one','second','2','dos','two','third','3','three','4' ]


It doesn't matter what order the items with similar index go as long as they are together, so a result of 'one','uno','1'... is a good as what's above. I would like to do it just using immutable variables if possible.



I have a way that works:



    const output = input.reduce((accumulator, currentArray, arrayIndex)=>{
currentArray.forEach((item,itemIndex)=>{
const newIndex = itemIndex*(arrayIndex+1);
accumulator.splice(newIndex<accumulator.length?newIndex:accumulator.length,0,item);
})
return accumulator;
})


But it's not very pretty and I don't like it, especially because of the way it mutates the accumulator in the forEach method. I feel there must be a more elegant method.



I can't believe no one has asked this before but I've tried a bunch of different queries and can't find it, so kindly tell me if it's there and I missed it. Is there a better way?



To clarify per question in comments, I would like to be able to do this without mutating any variables or arrays as I'm doing with the accumulator.splice and to only use functional methods such as .map, or .reduce not a mutating loop like a .forEach.










share|improve this question

























  • "Is there a better way?" What do you mean by "better"? "I don't like it" is not an objective coding problem. What is the requirement?

    – guest271314
    4 hours ago













  • Well for one thing I'd like to do it without mutating any variables, or introducing a .forEach loop which isn't really functional. And I think it can be done much more concisely as well. If I could zip a set of arrays together like in Python then reduce(concat) them together that way would work too.

    – jimboweb
    4 hours ago











  • I think I pretty clearly said I'd like the result to not mutate any arrays or variables, as I am doing with the accumulator.splice. That is an objective requirement.

    – jimboweb
    4 hours ago











  • Does the requirement include a restriction on using JSON.parse(JSON.stringify(input)) to avoid mutating the original array?

    – guest271314
    3 hours ago













  • Wow, lots of great answers, thanks. I'm a little torn on which one to accept as a solution, so I have to try them out. I'll choose a solution in a day or so. but I voted you all up. Thanks again.

    – jimboweb
    38 mins ago














6












6








6


1






I'm trying to use reduce() combine a set of arrays in a "collated" order so items with similar indexes are together. For example:



input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]

output = [ 'first','1','uno','one','second','2','dos','two','third','3','three','4' ]


It doesn't matter what order the items with similar index go as long as they are together, so a result of 'one','uno','1'... is a good as what's above. I would like to do it just using immutable variables if possible.



I have a way that works:



    const output = input.reduce((accumulator, currentArray, arrayIndex)=>{
currentArray.forEach((item,itemIndex)=>{
const newIndex = itemIndex*(arrayIndex+1);
accumulator.splice(newIndex<accumulator.length?newIndex:accumulator.length,0,item);
})
return accumulator;
})


But it's not very pretty and I don't like it, especially because of the way it mutates the accumulator in the forEach method. I feel there must be a more elegant method.



I can't believe no one has asked this before but I've tried a bunch of different queries and can't find it, so kindly tell me if it's there and I missed it. Is there a better way?



To clarify per question in comments, I would like to be able to do this without mutating any variables or arrays as I'm doing with the accumulator.splice and to only use functional methods such as .map, or .reduce not a mutating loop like a .forEach.










share|improve this question
















I'm trying to use reduce() combine a set of arrays in a "collated" order so items with similar indexes are together. For example:



input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]

output = [ 'first','1','uno','one','second','2','dos','two','third','3','three','4' ]


It doesn't matter what order the items with similar index go as long as they are together, so a result of 'one','uno','1'... is a good as what's above. I would like to do it just using immutable variables if possible.



I have a way that works:



    const output = input.reduce((accumulator, currentArray, arrayIndex)=>{
currentArray.forEach((item,itemIndex)=>{
const newIndex = itemIndex*(arrayIndex+1);
accumulator.splice(newIndex<accumulator.length?newIndex:accumulator.length,0,item);
})
return accumulator;
})


But it's not very pretty and I don't like it, especially because of the way it mutates the accumulator in the forEach method. I feel there must be a more elegant method.



I can't believe no one has asked this before but I've tried a bunch of different queries and can't find it, so kindly tell me if it's there and I missed it. Is there a better way?



To clarify per question in comments, I would like to be able to do this without mutating any variables or arrays as I'm doing with the accumulator.splice and to only use functional methods such as .map, or .reduce not a mutating loop like a .forEach.







javascript arrays functional-programming






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 4 hours ago







jimboweb

















asked 4 hours ago









jimbowebjimboweb

1,74111027




1,74111027













  • "Is there a better way?" What do you mean by "better"? "I don't like it" is not an objective coding problem. What is the requirement?

    – guest271314
    4 hours ago













  • Well for one thing I'd like to do it without mutating any variables, or introducing a .forEach loop which isn't really functional. And I think it can be done much more concisely as well. If I could zip a set of arrays together like in Python then reduce(concat) them together that way would work too.

    – jimboweb
    4 hours ago











  • I think I pretty clearly said I'd like the result to not mutate any arrays or variables, as I am doing with the accumulator.splice. That is an objective requirement.

    – jimboweb
    4 hours ago











  • Does the requirement include a restriction on using JSON.parse(JSON.stringify(input)) to avoid mutating the original array?

    – guest271314
    3 hours ago













  • Wow, lots of great answers, thanks. I'm a little torn on which one to accept as a solution, so I have to try them out. I'll choose a solution in a day or so. but I voted you all up. Thanks again.

    – jimboweb
    38 mins ago



















  • "Is there a better way?" What do you mean by "better"? "I don't like it" is not an objective coding problem. What is the requirement?

    – guest271314
    4 hours ago













  • Well for one thing I'd like to do it without mutating any variables, or introducing a .forEach loop which isn't really functional. And I think it can be done much more concisely as well. If I could zip a set of arrays together like in Python then reduce(concat) them together that way would work too.

    – jimboweb
    4 hours ago











  • I think I pretty clearly said I'd like the result to not mutate any arrays or variables, as I am doing with the accumulator.splice. That is an objective requirement.

    – jimboweb
    4 hours ago











  • Does the requirement include a restriction on using JSON.parse(JSON.stringify(input)) to avoid mutating the original array?

    – guest271314
    3 hours ago













  • Wow, lots of great answers, thanks. I'm a little torn on which one to accept as a solution, so I have to try them out. I'll choose a solution in a day or so. but I voted you all up. Thanks again.

    – jimboweb
    38 mins ago

















"Is there a better way?" What do you mean by "better"? "I don't like it" is not an objective coding problem. What is the requirement?

– guest271314
4 hours ago







"Is there a better way?" What do you mean by "better"? "I don't like it" is not an objective coding problem. What is the requirement?

– guest271314
4 hours ago















Well for one thing I'd like to do it without mutating any variables, or introducing a .forEach loop which isn't really functional. And I think it can be done much more concisely as well. If I could zip a set of arrays together like in Python then reduce(concat) them together that way would work too.

– jimboweb
4 hours ago





Well for one thing I'd like to do it without mutating any variables, or introducing a .forEach loop which isn't really functional. And I think it can be done much more concisely as well. If I could zip a set of arrays together like in Python then reduce(concat) them together that way would work too.

– jimboweb
4 hours ago













I think I pretty clearly said I'd like the result to not mutate any arrays or variables, as I am doing with the accumulator.splice. That is an objective requirement.

– jimboweb
4 hours ago





I think I pretty clearly said I'd like the result to not mutate any arrays or variables, as I am doing with the accumulator.splice. That is an objective requirement.

– jimboweb
4 hours ago













Does the requirement include a restriction on using JSON.parse(JSON.stringify(input)) to avoid mutating the original array?

– guest271314
3 hours ago







Does the requirement include a restriction on using JSON.parse(JSON.stringify(input)) to avoid mutating the original array?

– guest271314
3 hours ago















Wow, lots of great answers, thanks. I'm a little torn on which one to accept as a solution, so I have to try them out. I'll choose a solution in a day or so. but I voted you all up. Thanks again.

– jimboweb
38 mins ago





Wow, lots of great answers, thanks. I'm a little torn on which one to accept as a solution, so I have to try them out. I'll choose a solution in a day or so. but I voted you all up. Thanks again.

– jimboweb
38 mins ago












4 Answers
4






active

oldest

votes


















4














Maybe just a simple for... i loop that checks each array for an item in position i






var input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["1st","2nd","3rd"]]

var output =
var maxLen = Math.max(...input.map(arr => arr.length));

for (i=0; i < maxLen; i++) {
input.forEach(arr => { if (arr[i] !== undefined) output.push(arr[i]) })
}

console.log(output)





Simple, but predictable and readable





Avoiding For Each Loop



If you need to avoid forEach, here's a similar approach where you could: get the max child array length, build a range of integers that would've been created by the for loop ([1,2,3,4]), map each value to pivot the arrays, flatten the multi-dimensional array, and then filter out the empty cells.



First in discrete steps, and then as a one liner:



var input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["1st","2nd","3rd"]];


Multiple Steps:



var maxLen = Math.max(...input.map(arr => arr.length));
var indexes = Array(maxLen).fill().map((_,i) => i);
var pivoted = indexes.map(i => input.map(arr => arr[i] ));
var flattened = pivoted.flat().filter(el => el !== undefined);


One Liner:



var output = Array(Math.max(...input.map(arr => arr.length))).fill().map((_,i) => i)
.map(i => input.map(arr => arr[i] ))
.flat().filter(el => el !== undefined)





share|improve this answer

































    3














    Use Array.from() to create a new array with the length of the longest sub array. To get the length of the longest sub array, get an array of the lengths with Array.map() and take the max item.



    Then collect the non undefined items at the current index from each sub array with Array.reduceRight() or Array.reduce() (depending on the order you want), and use Array.flat() to get a single array.






    const input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]

    const result = Array.from({
    length: Math.max(...input.map(o => o.length))
    }, (_, i) => input.reduceRight((r, o) => o[i] === undefined ? r : [...r, o[i]], ))
    .flat();

    console.log(result);








    share|improve this answer


























    • Cool! I like it!

      – KyleMit
      3 hours ago











    • -4 bytes [...Array(Math.max(...input.map(o => o.length)))].map((_,i)=>{})

      – guest271314
      2 hours ago



















    2














    Funny solution




    1. add index as prefix on inner array

    2. Flatten the array

    3. sort the array

    4. Remove the prefix





    let input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]
    let ranked=input.map(i=>i.map((j,k)=>k+'---'+j)).slice()
    console.log(ranked.flat().sort().map(i=>i.split('---')[1]));








    share|improve this answer


























    • Clever answer. I did consider doing something like this. I was thinking of something more like making the inner map return something like {ind:k,val:j} followed by a .sort((a,b)=>return a.ind-b.ind) but it's the same idea. I decided against it because creating unnecessary objects (or strings) felt like doing unnecessary work. But still a good answer, thanks.

      – jimboweb
      29 mins ago






    • 1





      yes this is bit messy , i admit it

      – sumit
      27 mins ago



















    2














    Here I have provided a generator function that will yield the values in the desired order. You could easily turn this into a regular function returning an array if you replace the yield with a push to a results array to be returned.



    The algorithm takes in all the arrays as arguments, then gets the iterators for each of them. Then it enters the main loop where it treats the iters array like a queue, taking the iterator in front, yielding the next generated value, then placing it back at the end of the queue unless it is empty. The efficiency would improve if you transformed the array into a linked list where adding to the front and back take constant time, whereas a shift on an array is linear time to shift everything down one spot.



    function* collate(...arrays) {
    const iters = arrays.map(a => a.values());
    while(iters.length > 0) {
    const iter = iters.shift();
    const {done, value} = iter.next();
    if(done) continue;
    yield value;
    iters.push(iter);
    }
    }





    share|improve this answer



















    • 1





      This is a great answer, thanks. But the while loop felt kind of like the .forEach I was trying to get around. But it's still a good answer so I voted it up.

      – jimboweb
      26 mins ago











    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54796607%2freduce-array-of-arrays-into-on-array-in-collated-order%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    4 Answers
    4






    active

    oldest

    votes








    4 Answers
    4






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    4














    Maybe just a simple for... i loop that checks each array for an item in position i






    var input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["1st","2nd","3rd"]]

    var output =
    var maxLen = Math.max(...input.map(arr => arr.length));

    for (i=0; i < maxLen; i++) {
    input.forEach(arr => { if (arr[i] !== undefined) output.push(arr[i]) })
    }

    console.log(output)





    Simple, but predictable and readable





    Avoiding For Each Loop



    If you need to avoid forEach, here's a similar approach where you could: get the max child array length, build a range of integers that would've been created by the for loop ([1,2,3,4]), map each value to pivot the arrays, flatten the multi-dimensional array, and then filter out the empty cells.



    First in discrete steps, and then as a one liner:



    var input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["1st","2nd","3rd"]];


    Multiple Steps:



    var maxLen = Math.max(...input.map(arr => arr.length));
    var indexes = Array(maxLen).fill().map((_,i) => i);
    var pivoted = indexes.map(i => input.map(arr => arr[i] ));
    var flattened = pivoted.flat().filter(el => el !== undefined);


    One Liner:



    var output = Array(Math.max(...input.map(arr => arr.length))).fill().map((_,i) => i)
    .map(i => input.map(arr => arr[i] ))
    .flat().filter(el => el !== undefined)





    share|improve this answer






























      4














      Maybe just a simple for... i loop that checks each array for an item in position i






      var input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["1st","2nd","3rd"]]

      var output =
      var maxLen = Math.max(...input.map(arr => arr.length));

      for (i=0; i < maxLen; i++) {
      input.forEach(arr => { if (arr[i] !== undefined) output.push(arr[i]) })
      }

      console.log(output)





      Simple, but predictable and readable





      Avoiding For Each Loop



      If you need to avoid forEach, here's a similar approach where you could: get the max child array length, build a range of integers that would've been created by the for loop ([1,2,3,4]), map each value to pivot the arrays, flatten the multi-dimensional array, and then filter out the empty cells.



      First in discrete steps, and then as a one liner:



      var input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["1st","2nd","3rd"]];


      Multiple Steps:



      var maxLen = Math.max(...input.map(arr => arr.length));
      var indexes = Array(maxLen).fill().map((_,i) => i);
      var pivoted = indexes.map(i => input.map(arr => arr[i] ));
      var flattened = pivoted.flat().filter(el => el !== undefined);


      One Liner:



      var output = Array(Math.max(...input.map(arr => arr.length))).fill().map((_,i) => i)
      .map(i => input.map(arr => arr[i] ))
      .flat().filter(el => el !== undefined)





      share|improve this answer




























        4












        4








        4







        Maybe just a simple for... i loop that checks each array for an item in position i






        var input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["1st","2nd","3rd"]]

        var output =
        var maxLen = Math.max(...input.map(arr => arr.length));

        for (i=0; i < maxLen; i++) {
        input.forEach(arr => { if (arr[i] !== undefined) output.push(arr[i]) })
        }

        console.log(output)





        Simple, but predictable and readable





        Avoiding For Each Loop



        If you need to avoid forEach, here's a similar approach where you could: get the max child array length, build a range of integers that would've been created by the for loop ([1,2,3,4]), map each value to pivot the arrays, flatten the multi-dimensional array, and then filter out the empty cells.



        First in discrete steps, and then as a one liner:



        var input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["1st","2nd","3rd"]];


        Multiple Steps:



        var maxLen = Math.max(...input.map(arr => arr.length));
        var indexes = Array(maxLen).fill().map((_,i) => i);
        var pivoted = indexes.map(i => input.map(arr => arr[i] ));
        var flattened = pivoted.flat().filter(el => el !== undefined);


        One Liner:



        var output = Array(Math.max(...input.map(arr => arr.length))).fill().map((_,i) => i)
        .map(i => input.map(arr => arr[i] ))
        .flat().filter(el => el !== undefined)





        share|improve this answer















        Maybe just a simple for... i loop that checks each array for an item in position i






        var input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["1st","2nd","3rd"]]

        var output =
        var maxLen = Math.max(...input.map(arr => arr.length));

        for (i=0; i < maxLen; i++) {
        input.forEach(arr => { if (arr[i] !== undefined) output.push(arr[i]) })
        }

        console.log(output)





        Simple, but predictable and readable





        Avoiding For Each Loop



        If you need to avoid forEach, here's a similar approach where you could: get the max child array length, build a range of integers that would've been created by the for loop ([1,2,3,4]), map each value to pivot the arrays, flatten the multi-dimensional array, and then filter out the empty cells.



        First in discrete steps, and then as a one liner:



        var input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["1st","2nd","3rd"]];


        Multiple Steps:



        var maxLen = Math.max(...input.map(arr => arr.length));
        var indexes = Array(maxLen).fill().map((_,i) => i);
        var pivoted = indexes.map(i => input.map(arr => arr[i] ));
        var flattened = pivoted.flat().filter(el => el !== undefined);


        One Liner:



        var output = Array(Math.max(...input.map(arr => arr.length))).fill().map((_,i) => i)
        .map(i => input.map(arr => arr[i] ))
        .flat().filter(el => el !== undefined)





        var input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["1st","2nd","3rd"]]

        var output =
        var maxLen = Math.max(...input.map(arr => arr.length));

        for (i=0; i < maxLen; i++) {
        input.forEach(arr => { if (arr[i] !== undefined) output.push(arr[i]) })
        }

        console.log(output)





        var input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["1st","2nd","3rd"]]

        var output =
        var maxLen = Math.max(...input.map(arr => arr.length));

        for (i=0; i < maxLen; i++) {
        input.forEach(arr => { if (arr[i] !== undefined) output.push(arr[i]) })
        }

        console.log(output)






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 50 mins ago

























        answered 4 hours ago









        KyleMitKyleMit

        58.6k35241401




        58.6k35241401

























            3














            Use Array.from() to create a new array with the length of the longest sub array. To get the length of the longest sub array, get an array of the lengths with Array.map() and take the max item.



            Then collect the non undefined items at the current index from each sub array with Array.reduceRight() or Array.reduce() (depending on the order you want), and use Array.flat() to get a single array.






            const input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]

            const result = Array.from({
            length: Math.max(...input.map(o => o.length))
            }, (_, i) => input.reduceRight((r, o) => o[i] === undefined ? r : [...r, o[i]], ))
            .flat();

            console.log(result);








            share|improve this answer


























            • Cool! I like it!

              – KyleMit
              3 hours ago











            • -4 bytes [...Array(Math.max(...input.map(o => o.length)))].map((_,i)=>{})

              – guest271314
              2 hours ago
















            3














            Use Array.from() to create a new array with the length of the longest sub array. To get the length of the longest sub array, get an array of the lengths with Array.map() and take the max item.



            Then collect the non undefined items at the current index from each sub array with Array.reduceRight() or Array.reduce() (depending on the order you want), and use Array.flat() to get a single array.






            const input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]

            const result = Array.from({
            length: Math.max(...input.map(o => o.length))
            }, (_, i) => input.reduceRight((r, o) => o[i] === undefined ? r : [...r, o[i]], ))
            .flat();

            console.log(result);








            share|improve this answer


























            • Cool! I like it!

              – KyleMit
              3 hours ago











            • -4 bytes [...Array(Math.max(...input.map(o => o.length)))].map((_,i)=>{})

              – guest271314
              2 hours ago














            3












            3








            3







            Use Array.from() to create a new array with the length of the longest sub array. To get the length of the longest sub array, get an array of the lengths with Array.map() and take the max item.



            Then collect the non undefined items at the current index from each sub array with Array.reduceRight() or Array.reduce() (depending on the order you want), and use Array.flat() to get a single array.






            const input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]

            const result = Array.from({
            length: Math.max(...input.map(o => o.length))
            }, (_, i) => input.reduceRight((r, o) => o[i] === undefined ? r : [...r, o[i]], ))
            .flat();

            console.log(result);








            share|improve this answer















            Use Array.from() to create a new array with the length of the longest sub array. To get the length of the longest sub array, get an array of the lengths with Array.map() and take the max item.



            Then collect the non undefined items at the current index from each sub array with Array.reduceRight() or Array.reduce() (depending on the order you want), and use Array.flat() to get a single array.






            const input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]

            const result = Array.from({
            length: Math.max(...input.map(o => o.length))
            }, (_, i) => input.reduceRight((r, o) => o[i] === undefined ? r : [...r, o[i]], ))
            .flat();

            console.log(result);








            const input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]

            const result = Array.from({
            length: Math.max(...input.map(o => o.length))
            }, (_, i) => input.reduceRight((r, o) => o[i] === undefined ? r : [...r, o[i]], ))
            .flat();

            console.log(result);





            const input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]

            const result = Array.from({
            length: Math.max(...input.map(o => o.length))
            }, (_, i) => input.reduceRight((r, o) => o[i] === undefined ? r : [...r, o[i]], ))
            .flat();

            console.log(result);






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited 4 hours ago

























            answered 4 hours ago









            Ori DroriOri Drori

            77.9k138492




            77.9k138492













            • Cool! I like it!

              – KyleMit
              3 hours ago











            • -4 bytes [...Array(Math.max(...input.map(o => o.length)))].map((_,i)=>{})

              – guest271314
              2 hours ago



















            • Cool! I like it!

              – KyleMit
              3 hours ago











            • -4 bytes [...Array(Math.max(...input.map(o => o.length)))].map((_,i)=>{})

              – guest271314
              2 hours ago

















            Cool! I like it!

            – KyleMit
            3 hours ago





            Cool! I like it!

            – KyleMit
            3 hours ago













            -4 bytes [...Array(Math.max(...input.map(o => o.length)))].map((_,i)=>{})

            – guest271314
            2 hours ago





            -4 bytes [...Array(Math.max(...input.map(o => o.length)))].map((_,i)=>{})

            – guest271314
            2 hours ago











            2














            Funny solution




            1. add index as prefix on inner array

            2. Flatten the array

            3. sort the array

            4. Remove the prefix





            let input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]
            let ranked=input.map(i=>i.map((j,k)=>k+'---'+j)).slice()
            console.log(ranked.flat().sort().map(i=>i.split('---')[1]));








            share|improve this answer


























            • Clever answer. I did consider doing something like this. I was thinking of something more like making the inner map return something like {ind:k,val:j} followed by a .sort((a,b)=>return a.ind-b.ind) but it's the same idea. I decided against it because creating unnecessary objects (or strings) felt like doing unnecessary work. But still a good answer, thanks.

              – jimboweb
              29 mins ago






            • 1





              yes this is bit messy , i admit it

              – sumit
              27 mins ago
















            2














            Funny solution




            1. add index as prefix on inner array

            2. Flatten the array

            3. sort the array

            4. Remove the prefix





            let input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]
            let ranked=input.map(i=>i.map((j,k)=>k+'---'+j)).slice()
            console.log(ranked.flat().sort().map(i=>i.split('---')[1]));








            share|improve this answer


























            • Clever answer. I did consider doing something like this. I was thinking of something more like making the inner map return something like {ind:k,val:j} followed by a .sort((a,b)=>return a.ind-b.ind) but it's the same idea. I decided against it because creating unnecessary objects (or strings) felt like doing unnecessary work. But still a good answer, thanks.

              – jimboweb
              29 mins ago






            • 1





              yes this is bit messy , i admit it

              – sumit
              27 mins ago














            2












            2








            2







            Funny solution




            1. add index as prefix on inner array

            2. Flatten the array

            3. sort the array

            4. Remove the prefix





            let input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]
            let ranked=input.map(i=>i.map((j,k)=>k+'---'+j)).slice()
            console.log(ranked.flat().sort().map(i=>i.split('---')[1]));








            share|improve this answer















            Funny solution




            1. add index as prefix on inner array

            2. Flatten the array

            3. sort the array

            4. Remove the prefix





            let input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]
            let ranked=input.map(i=>i.map((j,k)=>k+'---'+j)).slice()
            console.log(ranked.flat().sort().map(i=>i.split('---')[1]));








            let input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]
            let ranked=input.map(i=>i.map((j,k)=>k+'---'+j)).slice()
            console.log(ranked.flat().sort().map(i=>i.split('---')[1]));





            let input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]
            let ranked=input.map(i=>i.map((j,k)=>k+'---'+j)).slice()
            console.log(ranked.flat().sort().map(i=>i.split('---')[1]));






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited 2 hours ago

























            answered 4 hours ago









            sumitsumit

            8,18993479




            8,18993479













            • Clever answer. I did consider doing something like this. I was thinking of something more like making the inner map return something like {ind:k,val:j} followed by a .sort((a,b)=>return a.ind-b.ind) but it's the same idea. I decided against it because creating unnecessary objects (or strings) felt like doing unnecessary work. But still a good answer, thanks.

              – jimboweb
              29 mins ago






            • 1





              yes this is bit messy , i admit it

              – sumit
              27 mins ago



















            • Clever answer. I did consider doing something like this. I was thinking of something more like making the inner map return something like {ind:k,val:j} followed by a .sort((a,b)=>return a.ind-b.ind) but it's the same idea. I decided against it because creating unnecessary objects (or strings) felt like doing unnecessary work. But still a good answer, thanks.

              – jimboweb
              29 mins ago






            • 1





              yes this is bit messy , i admit it

              – sumit
              27 mins ago

















            Clever answer. I did consider doing something like this. I was thinking of something more like making the inner map return something like {ind:k,val:j} followed by a .sort((a,b)=>return a.ind-b.ind) but it's the same idea. I decided against it because creating unnecessary objects (or strings) felt like doing unnecessary work. But still a good answer, thanks.

            – jimboweb
            29 mins ago





            Clever answer. I did consider doing something like this. I was thinking of something more like making the inner map return something like {ind:k,val:j} followed by a .sort((a,b)=>return a.ind-b.ind) but it's the same idea. I decided against it because creating unnecessary objects (or strings) felt like doing unnecessary work. But still a good answer, thanks.

            – jimboweb
            29 mins ago




            1




            1





            yes this is bit messy , i admit it

            – sumit
            27 mins ago





            yes this is bit messy , i admit it

            – sumit
            27 mins ago











            2














            Here I have provided a generator function that will yield the values in the desired order. You could easily turn this into a regular function returning an array if you replace the yield with a push to a results array to be returned.



            The algorithm takes in all the arrays as arguments, then gets the iterators for each of them. Then it enters the main loop where it treats the iters array like a queue, taking the iterator in front, yielding the next generated value, then placing it back at the end of the queue unless it is empty. The efficiency would improve if you transformed the array into a linked list where adding to the front and back take constant time, whereas a shift on an array is linear time to shift everything down one spot.



            function* collate(...arrays) {
            const iters = arrays.map(a => a.values());
            while(iters.length > 0) {
            const iter = iters.shift();
            const {done, value} = iter.next();
            if(done) continue;
            yield value;
            iters.push(iter);
            }
            }





            share|improve this answer



















            • 1





              This is a great answer, thanks. But the while loop felt kind of like the .forEach I was trying to get around. But it's still a good answer so I voted it up.

              – jimboweb
              26 mins ago
















            2














            Here I have provided a generator function that will yield the values in the desired order. You could easily turn this into a regular function returning an array if you replace the yield with a push to a results array to be returned.



            The algorithm takes in all the arrays as arguments, then gets the iterators for each of them. Then it enters the main loop where it treats the iters array like a queue, taking the iterator in front, yielding the next generated value, then placing it back at the end of the queue unless it is empty. The efficiency would improve if you transformed the array into a linked list where adding to the front and back take constant time, whereas a shift on an array is linear time to shift everything down one spot.



            function* collate(...arrays) {
            const iters = arrays.map(a => a.values());
            while(iters.length > 0) {
            const iter = iters.shift();
            const {done, value} = iter.next();
            if(done) continue;
            yield value;
            iters.push(iter);
            }
            }





            share|improve this answer



















            • 1





              This is a great answer, thanks. But the while loop felt kind of like the .forEach I was trying to get around. But it's still a good answer so I voted it up.

              – jimboweb
              26 mins ago














            2












            2








            2







            Here I have provided a generator function that will yield the values in the desired order. You could easily turn this into a regular function returning an array if you replace the yield with a push to a results array to be returned.



            The algorithm takes in all the arrays as arguments, then gets the iterators for each of them. Then it enters the main loop where it treats the iters array like a queue, taking the iterator in front, yielding the next generated value, then placing it back at the end of the queue unless it is empty. The efficiency would improve if you transformed the array into a linked list where adding to the front and back take constant time, whereas a shift on an array is linear time to shift everything down one spot.



            function* collate(...arrays) {
            const iters = arrays.map(a => a.values());
            while(iters.length > 0) {
            const iter = iters.shift();
            const {done, value} = iter.next();
            if(done) continue;
            yield value;
            iters.push(iter);
            }
            }





            share|improve this answer













            Here I have provided a generator function that will yield the values in the desired order. You could easily turn this into a regular function returning an array if you replace the yield with a push to a results array to be returned.



            The algorithm takes in all the arrays as arguments, then gets the iterators for each of them. Then it enters the main loop where it treats the iters array like a queue, taking the iterator in front, yielding the next generated value, then placing it back at the end of the queue unless it is empty. The efficiency would improve if you transformed the array into a linked list where adding to the front and back take constant time, whereas a shift on an array is linear time to shift everything down one spot.



            function* collate(...arrays) {
            const iters = arrays.map(a => a.values());
            while(iters.length > 0) {
            const iter = iters.shift();
            const {done, value} = iter.next();
            if(done) continue;
            yield value;
            iters.push(iter);
            }
            }






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered 2 hours ago









            kamoroso94kamoroso94

            1,38511316




            1,38511316








            • 1





              This is a great answer, thanks. But the while loop felt kind of like the .forEach I was trying to get around. But it's still a good answer so I voted it up.

              – jimboweb
              26 mins ago














            • 1





              This is a great answer, thanks. But the while loop felt kind of like the .forEach I was trying to get around. But it's still a good answer so I voted it up.

              – jimboweb
              26 mins ago








            1




            1





            This is a great answer, thanks. But the while loop felt kind of like the .forEach I was trying to get around. But it's still a good answer so I voted it up.

            – jimboweb
            26 mins ago





            This is a great answer, thanks. But the while loop felt kind of like the .forEach I was trying to get around. But it's still a good answer so I voted it up.

            – jimboweb
            26 mins ago


















            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54796607%2freduce-array-of-arrays-into-on-array-in-collated-order%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            What other Star Trek series did the main TNG cast show up in?

            Berlina muro

            Berlina aerponto