knot22
knot22

Reputation: 2768

cross join equivalent in JavaScript

In an app that's being developed there is a use case whereby dates need to be generated from an array of months and another array of years. Here is an example of representative data in those arrays:

const months= ["1", "4", "7", "9"];
const years = ["2021", "2022", "2027"];

The necessary result is the first day of each month + year combination, like so:

const dates = [
"1/1/2021", "4/1/2021", "7/1/2021", "9/1/2021",
"1/1/2022", "4/1/2022", "7/1/2022", "9/1/2022",
"1/1/2027", "4/1/2027", "7/1/2027", "9/1/2027"
];

The way I would do this in T-SQL is as follows -

select *
into #months
from
(
    values
    (1),
    (4),
    (7),
    (9)
) d (month);

select *
into #years
from
(
    values
    (2021),
    (2022),
    (2027)
) d (year);

select [dates] = datefromparts(year, month, 1)
from #months
cross join #years;

Output:
enter image description here

So, is there a cross join equivalent in Javascript? I'd rather use a concise approach like that rather than nested .forEach() statements.

Upvotes: 0

Views: 579

Answers (2)

joshwilsonvu
joshwilsonvu

Reputation: 2679

You can build that result by using Array#map() calls together, like so:

const months= ["1", "4", "7", "9"];
const years = ["2021", "2022", "2027"];
const dates = years.flatMap(year => {
  return months.map(month => `${month}/1/${year}`);
});
console.log(dates);

flatMap() is conceptually the same as map() and flat() together (but more performant).

const months= ["1", "4", "7", "9"];
const years = ["2021", "2022", "2027"];
const dates = years.map(year => {
  return months.map(month => `${month}/1/${year}`);
}).flat();
console.log(dates);

Upvotes: 1

Scott Sauyet
Scott Sauyet

Reputation: 50787

We can write a fairly simple crossproduct function that takes two arrays and a function and combines each pair of their product with the function.

It might look like this:

const crossproduct = (xs = [], ys = [], fn = (x, y) => [x, y]) =>
  xs .flatMap ((x) => ys .map ((y) => fn(x, y)))

const months= ["1", "4", "7", "9"]
const years = ["2021", "2022", "2027"]

const dates = crossproduct (years, months, (y, m) => `${m}/1/${y}`)

console .log (dates)
.as-console-wrapper {max-height: 100% !important; top: 0}

Note that crossproduct has a default function that just returns an array containing the two values. This is often useful.

Upvotes: 0

Related Questions