I'm dealing with OpenWeather API. My goal is to display the date and a timetable if that date (at any given time stamp) has windspeed >= MIN_WIND_SPEED
Edit: Added input and expected output JSON
The object returned from the API looks like this:
[
{
"dt": 1632808800,
"wind": {
"speed": 3.5
}
},
{
"dt": 1632819600,
"wind": {
"speed": 3.53
}
},
{
"dt": 1632830400,
"wind": {
"speed": 3.05
}
},
{
"dt": 1632841200,
"wind": {
"speed": 1.64
}
},
{
"dt": 1632852000,
"wind": {
"speed": 2.39
}
},
{
"dt": 1632862800,
"wind": {
"speed": 3.19
}
},
{
"dt": 1632873600,
"wind": {
"speed": 4.03
}
},
{
"dt": 1632884400,
"wind": {
"speed": 4.67
}
},
{
"dt": 1632895200,
"wind": {
"speed": 3.93
}
},
{
"dt": 1632906000,
"wind": {
"speed": 5.02
}
},
{
"dt": 1632916800,
"wind": {
"speed": 4.86
}
},
{
"dt": 1632927600,
"wind": {
"speed": 3.73
}
},
{
"dt": 1632938400,
"wind": {
"speed": 2.99
}
},
{
"dt": 1632949200,
"wind": {
"speed": 3.31
}
},
{
"dt": 1632960000,
"wind": {
"speed": 4.29
}
},
{
"dt": 1632970800,
"wind": {
"speed": 5.14
}
},
{
"dt": 1632981600,
"wind": {
"speed": 5.86
}
},
{
"dt": 1632992400,
"wind": {
"speed": 6.5
}
},
{
"dt": 1633003200,
"wind": {
"speed": 5.81
}
},
{
"dt": 1633014000,
"wind": {
"speed": 6.58
}
},
{
"dt": 1633024800,
"wind": {
"speed": 4.98
}
}
//...
]
I want to convert it into an object like this:
[
{
"key": "Saturday 09/25",
"value": [
{
"dt": 1632808800,
"wind": {
"speed": 3.5
}
},
{
"dt": 1632819600,
"wind": {
"speed": 3.53
}
},
{
"dt": 1632830400,
"wind": {
"speed": 3.05
}
},
{
"dt": 1632841200,
"wind": {
"speed": 1.64
}
},
{
"dt": 1632852000,
"wind": {
"speed": 2.39
}
},
{
"dt": 1632862800,
"wind": {
"speed": 3.19
}
}
]
},
{
"key": "Sunday 09/26",
"value": [
{
"dt": 1632808800,
"wind": {
"speed": 3.5
}
},
{
"dt": 1632819600,
"wind": {
"speed": 3.53
}
},
{
"dt": 1632830400,
"wind": {
"speed": 3.05
}
},
{
"dt": 1632841200,
"wind": {
"speed": 1.64
}
},
{
"dt": 1632852000,
"wind": {
"speed": 2.39
}
},
{
"dt": 1632862800,
"wind": {
"speed": 3.19
}
}
]
},
{
"key": "Monday 09/27",
"value": [
{
"dt": 1632808800,
"wind": {
"speed": 3.5
}
},
{
"dt": 1632819600,
"wind": {
"speed": 3.53
}
},
{
"dt": 1632830400,
"wind": {
"speed": 3.05
}
},
{
"dt": 1632841200,
"wind": {
"speed": 1.64
}
},
{
"dt": 1632852000,
"wind": {
"speed": 2.39
}
},
{
"dt": 1632862800,
"wind": {
"speed": 3.19
}
}
]
}
//...
]
The logic should convert dt
into dddd MM/DD
and group all the dt
of the same day together with key
being the date in human readable. It should also remove dates that does not have wind >= MIN_WIND_SPEED
I'm trying with these functions to filter the timestamp that has wind.speed
>= MIN_WIND_SPEED and group the entries by key dt
const list = weatherList.filter((i) => i.wind.speed >= MIN_WIND_SPEED);
const groupByDay = () =>
list.reduce((entryMap, entry) => {
let selector = unix(entry.dt).format("dddd MM/DD");
return entryMap.set(selector, [...(entryMap.get(selector) || []), entry]);
}, new Map());
This method removes all of the time stamps that does not have wind.speed >= MIN_WIND_SPEED. The results have the correct dates but the dates are missing the timestamps with wind.speed
< MIN_WIND_SPEED.
In this example, Saturday and Sunday should NOT be displayed! Because thay don't have any timestamp that has wind >= MIN_WIND_SPEED
Thanks!
CodePudding user response:
Can't you just but the boolean check inside the reduce function? If it doesn't pass, just return the map? I added a snippet below without the date formatting as it functions the same.
Edit: Added date formatting, not the same way you're doing it, but I believe this is the result you're after. Let me know if I'm wrong.
Edit 2: Updated the code snippet. The date key isn't exactly what you want, but I have to make dinner :P
const speeds = [{
"dt": 1632808800,
"wind": {
"speed": 3.5
}
},
{
"dt": 1432819600,
"wind": {
"speed": 3.53
}
},
{
"dt": 1632830400,
"wind": {
"speed": 3.05
}
},
{
"dt": 1632841200,
"wind": {
"speed": 1.64
}
}
]
const groupWindSpeedsByDay = (windSpeeds, minWindSpeed) => {
const grouped = windSpeeds.reduce((map, windSpeed) => {
if (windSpeed.wind.speed > minWindSpeed) {
const date = new Date()
date.setMilliseconds(windSpeed.dt)
const selector = `${date.toString().split(' ')[0]} ${date.getMonth() 1}/${date.getDate()}`;
map[selector] = map[selector] ? [...(map[selector]), windSpeed] : [windSpeed];
}
return map
}, {});
return Object.keys(grouped).map(key => ({
key: key,
values: grouped[key]
}));
}
console.log(groupWindSpeedsByDay(speeds, 3))
CodePudding user response:
This is just a 'group-by' with a boolean check before accumulating a given element.
Here accumulating into an object using reduce()
, and formatting the date using Intl.DateTimeFormat.
const input = [{ dt: 1632808800, wind: { speed: 3.5 }, }, { dt: 1632819600, wind: { speed: 3.53 }, }, { dt: 1632830400, wind: { speed: 3.05 }, }, { dt: 1632841200, wind: { speed: 1.64 }, }, { dt: 1632852000, wind: { speed: 2.39 }, }, { dt: 1632862800, wind: { speed: 3.19 }, }, { dt: 1632873600, wind: { speed: 4.03 }, }, { dt: 1632884400, wind: { speed: 4.67 }, }, { dt: 1632895200, wind: { speed: 3.93 }, }, { dt: 1632906000, wind: { speed: 5.02 }, }, { dt: 1632916800, wind: { speed: 4.86 }, }, { dt: 1632927600, wind: { speed: 3.73 }, }, { dt: 1632938400, wind: { speed: 2.99 }, }, { dt: 1632949200, wind: { speed: 3.31 }, }, { dt: 1632960000, wind: { speed: 4.29 }, }, { dt: 1632970800, wind: { speed: 5.14 }, }, { dt: 1632981600, wind: { speed: 5.86 }, }, { dt: 1632992400, wind: { speed: 6.5 }, }, { dt: 1633003200, wind: { speed: 5.81 }, }, { dt: 1633014000, wind: { speed: 6.58 }, }, { dt: 1633024800, wind: { speed: 4.98 }, },];
const MIN_WIND_SPEED = 4;
const result = Object.values(
input.reduce((a, o) => {
if (o.wind.speed >= MIN_WIND_SPEED) {
const date_string = new Intl.DateTimeFormat('default', {
weekday: 'long',
month: '2-digit',
day: '2-digit',
}).format(new Date(o.dt * 1000));
(a[date_string] ??= { key: date_string, value: [] }).value.push({ ...o });
}
return a;
}, {})
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Alternatively you could filter()
first and then reduce. Here accumulating into a Map
, returning an array using Array.from()
called on the result of the reduce, and pulling the date formatting out into its own helper function.
const input = [{ dt: 1632808800, wind: { speed: 3.5 }, }, { dt: 1632819600, wind: { speed: 3.53 }, }, { dt: 1632830400, wind: { speed: 3.05 }, }, { dt: 1632841200, wind: { speed: 1.64 }, }, { dt: 1632852000, wind: { speed: 2.39 }, }, { dt: 1632862800, wind: { speed: 3.19 }, }, { dt: 1632873600, wind: { speed: 4.03 }, }, { dt: 1632884400, wind: { speed: 4.67 }, }, { dt: 1632895200, wind: { speed: 3.93 }, }, { dt: 1632906000, wind: { speed: 5.02 }, }, { dt: 1632916800, wind: { speed: 4.86 }, }, { dt: 1632927600, wind: { speed: 3.73 }, }, { dt: 1632938400, wind: { speed: 2.99 }, }, { dt: 1632949200, wind: { speed: 3.31 }, }, { dt: 1632960000, wind: { speed: 4.29 }, }, { dt: 1632970800, wind: { speed: 5.14 }, }, { dt: 1632981600, wind: { speed: 5.86 }, }, { dt: 1632992400, wind: { speed: 6.5 }, }, { dt: 1633003200, wind: { speed: 5.81 }, }, { dt: 1633014000, wind: { speed: 6.58 }, }, { dt: 1633024800, wind: { speed: 4.98 }, },];
const ds = (dt) =>
new Intl.DateTimeFormat('default', {
weekday: 'long',
month: '2-digit',
day: '2-digit',
}).format(new Date(dt * 1000));
const MIN_WIND_SPEED = 4;
const result = Array.from(
input
.filter((o) => o.wind.speed >= MIN_WIND_SPEED) // filter by MIN_WIND_SPEED
.map((o) => ({ ds: ds(o.dt), ...o })) // map timestamp to date_string
.reduce((a, { ds, ...o }) => a.set(ds, [...(a.get(ds) ?? []), o]), new Map()), // reduce
// 'map' callback provided by Array.from() to refactor Map iterator
([key, values]) => ({ key, values })
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }