reduce array of arrays into on array in collated order
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
add a comment |
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
"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
8 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
8 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 theaccumulator.splice
. That is an objective requirement.
– jimboweb
8 hours ago
Does the requirement include a restriction on usingJSON.parse(JSON.stringify(input))
to avoid mutating the original array?
– guest271314
7 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
4 hours ago
add a comment |
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
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
javascript arrays functional-programming
edited 8 hours ago
jimboweb
asked 8 hours ago
jimbowebjimboweb
1,75611027
1,75611027
"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
8 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
8 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 theaccumulator.splice
. That is an objective requirement.
– jimboweb
8 hours ago
Does the requirement include a restriction on usingJSON.parse(JSON.stringify(input))
to avoid mutating the original array?
– guest271314
7 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
4 hours ago
add a comment |
"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
8 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
8 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 theaccumulator.splice
. That is an objective requirement.
– jimboweb
8 hours ago
Does the requirement include a restriction on usingJSON.parse(JSON.stringify(input))
to avoid mutating the original array?
– guest271314
7 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
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
8 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
8 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
8 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
8 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
8 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
8 hours ago
Does the requirement include a restriction on using
JSON.parse(JSON.stringify(input))
to avoid mutating the original array?– guest271314
7 hours ago
Does the requirement include a restriction on using
JSON.parse(JSON.stringify(input))
to avoid mutating the original array?– guest271314
7 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
4 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
4 hours ago
add a comment |
7 Answers
7
active
oldest
votes
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)
add a comment |
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);
Cool! I like it!
– KyleMit
7 hours ago
-4 bytes[...Array(Math.max(...input.map(o => o.length)))].map((_,i)=>{})
– guest271314
6 hours ago
@guest271314 - you'll need to fill the array afterwards, because you can't map sparse items.
– Ori Drori
1 hour ago
add a comment |
Funny solution
- add index as prefix on inner array
- Flatten the array
- sort the array
- 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]));
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
4 hours ago
1
yes this is bit messy , i admit it
– sumit
4 hours ago
add a comment |
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);
}
}
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
4 hours ago
add a comment |
I made it with recursion approach to avoid mutation.
let input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]
function recursion(input, idx = 0) {
let tmp = input.map(elm => elm[idx])
.filter(e => e !== undefined)
return tmp[0] ? tmp.concat(recursion(input, idx + 1)) :
}
console.log(recursion(input))
Oh I like that! I didn't even think of using recursion. That's very elegant.
– jimboweb
2 hours ago
add a comment |
Here's a recursive solution that meets the standards of elegance that you specified:
const head = xs => xs[0];
const tail = xs => xs.slice(1);
const notNull = xs => xs.length > 0;
console.log(collate([ ["one", "two", "three"]
, ["uno", "dos"]
, ["1", "2", "3", "4"]
, ["first", "second", "third"]
]));
function collate(xss) {
if (xss.length === 0) return ;
const yss = xss.filter(notNull);
return yss.map(head).concat(collate(yss.map(tail)));
}
It can be directly translated into Haskell code:
collate :: [[a]] -> [a]
collate =
collate xss = let yss = filter (not . null) xss
in map head yss ++ collate (map tail yss)
The previous solution took big steps to compute the answer. Here's a recursive solution that takes small steps to compute the answer:
console.log(collate([ ["one", "two", "three"]
, ["uno", "dos"]
, ["1", "2", "3", "4"]
, ["first", "second", "third"]
]));
function collate(xss_) {
if (xss_.length === 0) return ;
const [xs_, ...xss] = xss_;
if (xs_.length === 0) return collate(xss);
const [x, ...xs] = xs_;
return [x, ...collate(xss.concat([xs]))];
}
Here's the equivalent Haskell code:
collate :: [[a]] -> [a]
collate =
collate (:xss) = collate xss
collate ((x:xs):xss) = x : collate (xss ++ [xs])
Hope that helps.
add a comment |
I've seen the problem called round-robin. I think a collate
has a beautiful recursive definition -
const collate = ([ v, ...vs ], acc = ) =>
v === undefined
? acc
: isEmpty (v)
? collate (vs, acc)
: collate
( [ ...vs, tail (v) ]
, [ ...acc, head (v) ]
)
The dependencies are isEmpty
, tail
, and head
-
const isEmpty = xs =>
xs.length === 0
const head = ([ x, ...xs ]) =>
x
const tail = ([ x, ...xs ]) =>
xs
It works like this -
const input =
[ [ "one", "two", "three" ]
, [ "uno", "dos" ]
, [ "1", "2", "3", "4" ]
, [ "first", "second", "third" ]
]
console.log (collate (input))
// [ "one"
// , "uno"
// , "1"
// , "first"
// , "two"
// , "dos"
// , "2"
// , "second"
// , "three"
// , "3"
// , "third"
// , "4"
// ]
Verify the results in your own browser below -
const isEmpty = xs =>
xs.length === 0
const head = ([ x , ...xs ]) =>
x
const tail = ([ x , ...xs ]) =>
xs
const collate = ([ v, ...vs ], acc = ) =>
v === undefined
? acc
: isEmpty (v)
? collate (vs, acc)
: collate
( [ ...vs, tail (v) ]
, [ ...acc, head (v) ]
)
const input =
[ [ "one", "two", "three" ]
, [ "uno", "dos" ]
, [ "1", "2", "3", "4" ]
, [ "first", "second", "third" ]
]
console.log (collate (input))
// [ "one"
// , "uno"
// , "1"
// , "first"
// , "two"
// , "dos"
// , "2"
// , "second"
// , "three"
// , "3"
// , "third"
// , "4"
// ]
Thev === undefined
pattern is a terrible way to test whether an array is empty. What if the input was a sparse array such as[,2,3]
? The only reliable way to test whether an array is empty is to check itslength
property.
– Aadit M Shah
33 mins ago
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
7 Answers
7
active
oldest
votes
7 Answers
7
active
oldest
votes
active
oldest
votes
active
oldest
votes
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)
add a comment |
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)
add a comment |
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)
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)
edited 4 hours ago
answered 8 hours ago
KyleMitKyleMit
58.6k35241401
58.6k35241401
add a comment |
add a comment |
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);
Cool! I like it!
– KyleMit
7 hours ago
-4 bytes[...Array(Math.max(...input.map(o => o.length)))].map((_,i)=>{})
– guest271314
6 hours ago
@guest271314 - you'll need to fill the array afterwards, because you can't map sparse items.
– Ori Drori
1 hour ago
add a comment |
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);
Cool! I like it!
– KyleMit
7 hours ago
-4 bytes[...Array(Math.max(...input.map(o => o.length)))].map((_,i)=>{})
– guest271314
6 hours ago
@guest271314 - you'll need to fill the array afterwards, because you can't map sparse items.
– Ori Drori
1 hour ago
add a comment |
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);
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);
edited 1 hour ago
answered 8 hours ago
Ori DroriOri Drori
77.9k138492
77.9k138492
Cool! I like it!
– KyleMit
7 hours ago
-4 bytes[...Array(Math.max(...input.map(o => o.length)))].map((_,i)=>{})
– guest271314
6 hours ago
@guest271314 - you'll need to fill the array afterwards, because you can't map sparse items.
– Ori Drori
1 hour ago
add a comment |
Cool! I like it!
– KyleMit
7 hours ago
-4 bytes[...Array(Math.max(...input.map(o => o.length)))].map((_,i)=>{})
– guest271314
6 hours ago
@guest271314 - you'll need to fill the array afterwards, because you can't map sparse items.
– Ori Drori
1 hour ago
Cool! I like it!
– KyleMit
7 hours ago
Cool! I like it!
– KyleMit
7 hours ago
-4 bytes
[...Array(Math.max(...input.map(o => o.length)))].map((_,i)=>{})
– guest271314
6 hours ago
-4 bytes
[...Array(Math.max(...input.map(o => o.length)))].map((_,i)=>{})
– guest271314
6 hours ago
@guest271314 - you'll need to fill the array afterwards, because you can't map sparse items.
– Ori Drori
1 hour ago
@guest271314 - you'll need to fill the array afterwards, because you can't map sparse items.
– Ori Drori
1 hour ago
add a comment |
Funny solution
- add index as prefix on inner array
- Flatten the array
- sort the array
- 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]));
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
4 hours ago
1
yes this is bit messy , i admit it
– sumit
4 hours ago
add a comment |
Funny solution
- add index as prefix on inner array
- Flatten the array
- sort the array
- 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]));
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
4 hours ago
1
yes this is bit messy , i admit it
– sumit
4 hours ago
add a comment |
Funny solution
- add index as prefix on inner array
- Flatten the array
- sort the array
- 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]));
Funny solution
- add index as prefix on inner array
- Flatten the array
- sort the array
- 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]));
edited 6 hours ago
answered 7 hours ago
sumitsumit
8,20893479
8,20893479
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
4 hours ago
1
yes this is bit messy , i admit it
– sumit
4 hours ago
add a comment |
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
4 hours ago
1
yes this is bit messy , i admit it
– sumit
4 hours 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
4 hours 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
4 hours ago
1
1
yes this is bit messy , i admit it
– sumit
4 hours ago
yes this is bit messy , i admit it
– sumit
4 hours ago
add a comment |
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);
}
}
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
4 hours ago
add a comment |
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);
}
}
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
4 hours ago
add a comment |
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);
}
}
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);
}
}
answered 6 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
4 hours ago
add a comment |
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
4 hours 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
4 hours 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
4 hours ago
add a comment |
I made it with recursion approach to avoid mutation.
let input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]
function recursion(input, idx = 0) {
let tmp = input.map(elm => elm[idx])
.filter(e => e !== undefined)
return tmp[0] ? tmp.concat(recursion(input, idx + 1)) :
}
console.log(recursion(input))
Oh I like that! I didn't even think of using recursion. That's very elegant.
– jimboweb
2 hours ago
add a comment |
I made it with recursion approach to avoid mutation.
let input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]
function recursion(input, idx = 0) {
let tmp = input.map(elm => elm[idx])
.filter(e => e !== undefined)
return tmp[0] ? tmp.concat(recursion(input, idx + 1)) :
}
console.log(recursion(input))
Oh I like that! I didn't even think of using recursion. That's very elegant.
– jimboweb
2 hours ago
add a comment |
I made it with recursion approach to avoid mutation.
let input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]
function recursion(input, idx = 0) {
let tmp = input.map(elm => elm[idx])
.filter(e => e !== undefined)
return tmp[0] ? tmp.concat(recursion(input, idx + 1)) :
}
console.log(recursion(input))
I made it with recursion approach to avoid mutation.
let input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]
function recursion(input, idx = 0) {
let tmp = input.map(elm => elm[idx])
.filter(e => e !== undefined)
return tmp[0] ? tmp.concat(recursion(input, idx + 1)) :
}
console.log(recursion(input))
let input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]
function recursion(input, idx = 0) {
let tmp = input.map(elm => elm[idx])
.filter(e => e !== undefined)
return tmp[0] ? tmp.concat(recursion(input, idx + 1)) :
}
console.log(recursion(input))
let input = [["one","two","three"],["uno","dos"],["1","2","3","4"],["first","second","third"]]
function recursion(input, idx = 0) {
let tmp = input.map(elm => elm[idx])
.filter(e => e !== undefined)
return tmp[0] ? tmp.concat(recursion(input, idx + 1)) :
}
console.log(recursion(input))
edited 2 hours ago
answered 3 hours ago
Tam DcTam Dc
115412
115412
Oh I like that! I didn't even think of using recursion. That's very elegant.
– jimboweb
2 hours ago
add a comment |
Oh I like that! I didn't even think of using recursion. That's very elegant.
– jimboweb
2 hours ago
Oh I like that! I didn't even think of using recursion. That's very elegant.
– jimboweb
2 hours ago
Oh I like that! I didn't even think of using recursion. That's very elegant.
– jimboweb
2 hours ago
add a comment |
Here's a recursive solution that meets the standards of elegance that you specified:
const head = xs => xs[0];
const tail = xs => xs.slice(1);
const notNull = xs => xs.length > 0;
console.log(collate([ ["one", "two", "three"]
, ["uno", "dos"]
, ["1", "2", "3", "4"]
, ["first", "second", "third"]
]));
function collate(xss) {
if (xss.length === 0) return ;
const yss = xss.filter(notNull);
return yss.map(head).concat(collate(yss.map(tail)));
}
It can be directly translated into Haskell code:
collate :: [[a]] -> [a]
collate =
collate xss = let yss = filter (not . null) xss
in map head yss ++ collate (map tail yss)
The previous solution took big steps to compute the answer. Here's a recursive solution that takes small steps to compute the answer:
console.log(collate([ ["one", "two", "three"]
, ["uno", "dos"]
, ["1", "2", "3", "4"]
, ["first", "second", "third"]
]));
function collate(xss_) {
if (xss_.length === 0) return ;
const [xs_, ...xss] = xss_;
if (xs_.length === 0) return collate(xss);
const [x, ...xs] = xs_;
return [x, ...collate(xss.concat([xs]))];
}
Here's the equivalent Haskell code:
collate :: [[a]] -> [a]
collate =
collate (:xss) = collate xss
collate ((x:xs):xss) = x : collate (xss ++ [xs])
Hope that helps.
add a comment |
Here's a recursive solution that meets the standards of elegance that you specified:
const head = xs => xs[0];
const tail = xs => xs.slice(1);
const notNull = xs => xs.length > 0;
console.log(collate([ ["one", "two", "three"]
, ["uno", "dos"]
, ["1", "2", "3", "4"]
, ["first", "second", "third"]
]));
function collate(xss) {
if (xss.length === 0) return ;
const yss = xss.filter(notNull);
return yss.map(head).concat(collate(yss.map(tail)));
}
It can be directly translated into Haskell code:
collate :: [[a]] -> [a]
collate =
collate xss = let yss = filter (not . null) xss
in map head yss ++ collate (map tail yss)
The previous solution took big steps to compute the answer. Here's a recursive solution that takes small steps to compute the answer:
console.log(collate([ ["one", "two", "three"]
, ["uno", "dos"]
, ["1", "2", "3", "4"]
, ["first", "second", "third"]
]));
function collate(xss_) {
if (xss_.length === 0) return ;
const [xs_, ...xss] = xss_;
if (xs_.length === 0) return collate(xss);
const [x, ...xs] = xs_;
return [x, ...collate(xss.concat([xs]))];
}
Here's the equivalent Haskell code:
collate :: [[a]] -> [a]
collate =
collate (:xss) = collate xss
collate ((x:xs):xss) = x : collate (xss ++ [xs])
Hope that helps.
add a comment |
Here's a recursive solution that meets the standards of elegance that you specified:
const head = xs => xs[0];
const tail = xs => xs.slice(1);
const notNull = xs => xs.length > 0;
console.log(collate([ ["one", "two", "three"]
, ["uno", "dos"]
, ["1", "2", "3", "4"]
, ["first", "second", "third"]
]));
function collate(xss) {
if (xss.length === 0) return ;
const yss = xss.filter(notNull);
return yss.map(head).concat(collate(yss.map(tail)));
}
It can be directly translated into Haskell code:
collate :: [[a]] -> [a]
collate =
collate xss = let yss = filter (not . null) xss
in map head yss ++ collate (map tail yss)
The previous solution took big steps to compute the answer. Here's a recursive solution that takes small steps to compute the answer:
console.log(collate([ ["one", "two", "three"]
, ["uno", "dos"]
, ["1", "2", "3", "4"]
, ["first", "second", "third"]
]));
function collate(xss_) {
if (xss_.length === 0) return ;
const [xs_, ...xss] = xss_;
if (xs_.length === 0) return collate(xss);
const [x, ...xs] = xs_;
return [x, ...collate(xss.concat([xs]))];
}
Here's the equivalent Haskell code:
collate :: [[a]] -> [a]
collate =
collate (:xss) = collate xss
collate ((x:xs):xss) = x : collate (xss ++ [xs])
Hope that helps.
Here's a recursive solution that meets the standards of elegance that you specified:
const head = xs => xs[0];
const tail = xs => xs.slice(1);
const notNull = xs => xs.length > 0;
console.log(collate([ ["one", "two", "three"]
, ["uno", "dos"]
, ["1", "2", "3", "4"]
, ["first", "second", "third"]
]));
function collate(xss) {
if (xss.length === 0) return ;
const yss = xss.filter(notNull);
return yss.map(head).concat(collate(yss.map(tail)));
}
It can be directly translated into Haskell code:
collate :: [[a]] -> [a]
collate =
collate xss = let yss = filter (not . null) xss
in map head yss ++ collate (map tail yss)
The previous solution took big steps to compute the answer. Here's a recursive solution that takes small steps to compute the answer:
console.log(collate([ ["one", "two", "three"]
, ["uno", "dos"]
, ["1", "2", "3", "4"]
, ["first", "second", "third"]
]));
function collate(xss_) {
if (xss_.length === 0) return ;
const [xs_, ...xss] = xss_;
if (xs_.length === 0) return collate(xss);
const [x, ...xs] = xs_;
return [x, ...collate(xss.concat([xs]))];
}
Here's the equivalent Haskell code:
collate :: [[a]] -> [a]
collate =
collate (:xss) = collate xss
collate ((x:xs):xss) = x : collate (xss ++ [xs])
Hope that helps.
const head = xs => xs[0];
const tail = xs => xs.slice(1);
const notNull = xs => xs.length > 0;
console.log(collate([ ["one", "two", "three"]
, ["uno", "dos"]
, ["1", "2", "3", "4"]
, ["first", "second", "third"]
]));
function collate(xss) {
if (xss.length === 0) return ;
const yss = xss.filter(notNull);
return yss.map(head).concat(collate(yss.map(tail)));
}
const head = xs => xs[0];
const tail = xs => xs.slice(1);
const notNull = xs => xs.length > 0;
console.log(collate([ ["one", "two", "three"]
, ["uno", "dos"]
, ["1", "2", "3", "4"]
, ["first", "second", "third"]
]));
function collate(xss) {
if (xss.length === 0) return ;
const yss = xss.filter(notNull);
return yss.map(head).concat(collate(yss.map(tail)));
}
console.log(collate([ ["one", "two", "three"]
, ["uno", "dos"]
, ["1", "2", "3", "4"]
, ["first", "second", "third"]
]));
function collate(xss_) {
if (xss_.length === 0) return ;
const [xs_, ...xss] = xss_;
if (xs_.length === 0) return collate(xss);
const [x, ...xs] = xs_;
return [x, ...collate(xss.concat([xs]))];
}
console.log(collate([ ["one", "two", "three"]
, ["uno", "dos"]
, ["1", "2", "3", "4"]
, ["first", "second", "third"]
]));
function collate(xss_) {
if (xss_.length === 0) return ;
const [xs_, ...xss] = xss_;
if (xs_.length === 0) return collate(xss);
const [x, ...xs] = xs_;
return [x, ...collate(xss.concat([xs]))];
}
edited 40 mins ago
answered 2 hours ago
Aadit M ShahAadit M Shah
49.8k18111226
49.8k18111226
add a comment |
add a comment |
I've seen the problem called round-robin. I think a collate
has a beautiful recursive definition -
const collate = ([ v, ...vs ], acc = ) =>
v === undefined
? acc
: isEmpty (v)
? collate (vs, acc)
: collate
( [ ...vs, tail (v) ]
, [ ...acc, head (v) ]
)
The dependencies are isEmpty
, tail
, and head
-
const isEmpty = xs =>
xs.length === 0
const head = ([ x, ...xs ]) =>
x
const tail = ([ x, ...xs ]) =>
xs
It works like this -
const input =
[ [ "one", "two", "three" ]
, [ "uno", "dos" ]
, [ "1", "2", "3", "4" ]
, [ "first", "second", "third" ]
]
console.log (collate (input))
// [ "one"
// , "uno"
// , "1"
// , "first"
// , "two"
// , "dos"
// , "2"
// , "second"
// , "three"
// , "3"
// , "third"
// , "4"
// ]
Verify the results in your own browser below -
const isEmpty = xs =>
xs.length === 0
const head = ([ x , ...xs ]) =>
x
const tail = ([ x , ...xs ]) =>
xs
const collate = ([ v, ...vs ], acc = ) =>
v === undefined
? acc
: isEmpty (v)
? collate (vs, acc)
: collate
( [ ...vs, tail (v) ]
, [ ...acc, head (v) ]
)
const input =
[ [ "one", "two", "three" ]
, [ "uno", "dos" ]
, [ "1", "2", "3", "4" ]
, [ "first", "second", "third" ]
]
console.log (collate (input))
// [ "one"
// , "uno"
// , "1"
// , "first"
// , "two"
// , "dos"
// , "2"
// , "second"
// , "three"
// , "3"
// , "third"
// , "4"
// ]
Thev === undefined
pattern is a terrible way to test whether an array is empty. What if the input was a sparse array such as[,2,3]
? The only reliable way to test whether an array is empty is to check itslength
property.
– Aadit M Shah
33 mins ago
add a comment |
I've seen the problem called round-robin. I think a collate
has a beautiful recursive definition -
const collate = ([ v, ...vs ], acc = ) =>
v === undefined
? acc
: isEmpty (v)
? collate (vs, acc)
: collate
( [ ...vs, tail (v) ]
, [ ...acc, head (v) ]
)
The dependencies are isEmpty
, tail
, and head
-
const isEmpty = xs =>
xs.length === 0
const head = ([ x, ...xs ]) =>
x
const tail = ([ x, ...xs ]) =>
xs
It works like this -
const input =
[ [ "one", "two", "three" ]
, [ "uno", "dos" ]
, [ "1", "2", "3", "4" ]
, [ "first", "second", "third" ]
]
console.log (collate (input))
// [ "one"
// , "uno"
// , "1"
// , "first"
// , "two"
// , "dos"
// , "2"
// , "second"
// , "three"
// , "3"
// , "third"
// , "4"
// ]
Verify the results in your own browser below -
const isEmpty = xs =>
xs.length === 0
const head = ([ x , ...xs ]) =>
x
const tail = ([ x , ...xs ]) =>
xs
const collate = ([ v, ...vs ], acc = ) =>
v === undefined
? acc
: isEmpty (v)
? collate (vs, acc)
: collate
( [ ...vs, tail (v) ]
, [ ...acc, head (v) ]
)
const input =
[ [ "one", "two", "three" ]
, [ "uno", "dos" ]
, [ "1", "2", "3", "4" ]
, [ "first", "second", "third" ]
]
console.log (collate (input))
// [ "one"
// , "uno"
// , "1"
// , "first"
// , "two"
// , "dos"
// , "2"
// , "second"
// , "three"
// , "3"
// , "third"
// , "4"
// ]
Thev === undefined
pattern is a terrible way to test whether an array is empty. What if the input was a sparse array such as[,2,3]
? The only reliable way to test whether an array is empty is to check itslength
property.
– Aadit M Shah
33 mins ago
add a comment |
I've seen the problem called round-robin. I think a collate
has a beautiful recursive definition -
const collate = ([ v, ...vs ], acc = ) =>
v === undefined
? acc
: isEmpty (v)
? collate (vs, acc)
: collate
( [ ...vs, tail (v) ]
, [ ...acc, head (v) ]
)
The dependencies are isEmpty
, tail
, and head
-
const isEmpty = xs =>
xs.length === 0
const head = ([ x, ...xs ]) =>
x
const tail = ([ x, ...xs ]) =>
xs
It works like this -
const input =
[ [ "one", "two", "three" ]
, [ "uno", "dos" ]
, [ "1", "2", "3", "4" ]
, [ "first", "second", "third" ]
]
console.log (collate (input))
// [ "one"
// , "uno"
// , "1"
// , "first"
// , "two"
// , "dos"
// , "2"
// , "second"
// , "three"
// , "3"
// , "third"
// , "4"
// ]
Verify the results in your own browser below -
const isEmpty = xs =>
xs.length === 0
const head = ([ x , ...xs ]) =>
x
const tail = ([ x , ...xs ]) =>
xs
const collate = ([ v, ...vs ], acc = ) =>
v === undefined
? acc
: isEmpty (v)
? collate (vs, acc)
: collate
( [ ...vs, tail (v) ]
, [ ...acc, head (v) ]
)
const input =
[ [ "one", "two", "three" ]
, [ "uno", "dos" ]
, [ "1", "2", "3", "4" ]
, [ "first", "second", "third" ]
]
console.log (collate (input))
// [ "one"
// , "uno"
// , "1"
// , "first"
// , "two"
// , "dos"
// , "2"
// , "second"
// , "three"
// , "3"
// , "third"
// , "4"
// ]
I've seen the problem called round-robin. I think a collate
has a beautiful recursive definition -
const collate = ([ v, ...vs ], acc = ) =>
v === undefined
? acc
: isEmpty (v)
? collate (vs, acc)
: collate
( [ ...vs, tail (v) ]
, [ ...acc, head (v) ]
)
The dependencies are isEmpty
, tail
, and head
-
const isEmpty = xs =>
xs.length === 0
const head = ([ x, ...xs ]) =>
x
const tail = ([ x, ...xs ]) =>
xs
It works like this -
const input =
[ [ "one", "two", "three" ]
, [ "uno", "dos" ]
, [ "1", "2", "3", "4" ]
, [ "first", "second", "third" ]
]
console.log (collate (input))
// [ "one"
// , "uno"
// , "1"
// , "first"
// , "two"
// , "dos"
// , "2"
// , "second"
// , "three"
// , "3"
// , "third"
// , "4"
// ]
Verify the results in your own browser below -
const isEmpty = xs =>
xs.length === 0
const head = ([ x , ...xs ]) =>
x
const tail = ([ x , ...xs ]) =>
xs
const collate = ([ v, ...vs ], acc = ) =>
v === undefined
? acc
: isEmpty (v)
? collate (vs, acc)
: collate
( [ ...vs, tail (v) ]
, [ ...acc, head (v) ]
)
const input =
[ [ "one", "two", "three" ]
, [ "uno", "dos" ]
, [ "1", "2", "3", "4" ]
, [ "first", "second", "third" ]
]
console.log (collate (input))
// [ "one"
// , "uno"
// , "1"
// , "first"
// , "two"
// , "dos"
// , "2"
// , "second"
// , "three"
// , "3"
// , "third"
// , "4"
// ]
const isEmpty = xs =>
xs.length === 0
const head = ([ x , ...xs ]) =>
x
const tail = ([ x , ...xs ]) =>
xs
const collate = ([ v, ...vs ], acc = ) =>
v === undefined
? acc
: isEmpty (v)
? collate (vs, acc)
: collate
( [ ...vs, tail (v) ]
, [ ...acc, head (v) ]
)
const input =
[ [ "one", "two", "three" ]
, [ "uno", "dos" ]
, [ "1", "2", "3", "4" ]
, [ "first", "second", "third" ]
]
console.log (collate (input))
// [ "one"
// , "uno"
// , "1"
// , "first"
// , "two"
// , "dos"
// , "2"
// , "second"
// , "three"
// , "3"
// , "third"
// , "4"
// ]
const isEmpty = xs =>
xs.length === 0
const head = ([ x , ...xs ]) =>
x
const tail = ([ x , ...xs ]) =>
xs
const collate = ([ v, ...vs ], acc = ) =>
v === undefined
? acc
: isEmpty (v)
? collate (vs, acc)
: collate
( [ ...vs, tail (v) ]
, [ ...acc, head (v) ]
)
const input =
[ [ "one", "two", "three" ]
, [ "uno", "dos" ]
, [ "1", "2", "3", "4" ]
, [ "first", "second", "third" ]
]
console.log (collate (input))
// [ "one"
// , "uno"
// , "1"
// , "first"
// , "two"
// , "dos"
// , "2"
// , "second"
// , "three"
// , "3"
// , "third"
// , "4"
// ]
edited 53 mins ago
answered 1 hour ago
user633183user633183
70.6k21139180
70.6k21139180
Thev === undefined
pattern is a terrible way to test whether an array is empty. What if the input was a sparse array such as[,2,3]
? The only reliable way to test whether an array is empty is to check itslength
property.
– Aadit M Shah
33 mins ago
add a comment |
Thev === undefined
pattern is a terrible way to test whether an array is empty. What if the input was a sparse array such as[,2,3]
? The only reliable way to test whether an array is empty is to check itslength
property.
– Aadit M Shah
33 mins ago
The
v === undefined
pattern is a terrible way to test whether an array is empty. What if the input was a sparse array such as [,2,3]
? The only reliable way to test whether an array is empty is to check its length
property.– Aadit M Shah
33 mins ago
The
v === undefined
pattern is a terrible way to test whether an array is empty. What if the input was a sparse array such as [,2,3]
? The only reliable way to test whether an array is empty is to check its length
property.– Aadit M Shah
33 mins ago
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
"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
8 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
8 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
8 hours ago
Does the requirement include a restriction on using
JSON.parse(JSON.stringify(input))
to avoid mutating the original array?– guest271314
7 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
4 hours ago