Reputation: 115
I have a an array of objects named data
and need to return values for every day of a given period. The function should return 0 if there's no data for a day in the data
array. My reduce
function returns the wrong result. Also, I tried writing it with functions keyBy
and get
from lodash but have no idea how (my attempts didn't work). Can anyone help?
import { keyBy, get } from 'lodash';
import { eachDayOfInterval, format } from 'date-fns';
const data = [
{ value: 12, date: '02.08.2019' },
{ value: 34, date: '03.08.2019' },
{ value: 65, date: '05.08.2019' },
{ value: 8, date: '11.08.2019' },
{ value: 30, date: '14.08.2019' },
{ value: 87, date: '25.08.2019' },
];
const beginDate = '2019-08-01';
const endDate = '2019-08-06';
const dataSet = (data, begin, end) => {
const daysInterval = eachDayOfInterval({
start: new Date(begin),
end: new Date(end),
});
const days = daysInterval.map((date) => format(date, 'dd.MM.yyyy'));
//days array from period (dd.MM.yyyy)
const result = days.reduce((acc, day) => {
const newValue = data.map(v => (data.date === day) ? data.value : 0);
//const newValue = acc[year] ? acc[year] + 1 : 1;
obj.push({value: newValue, date: day});
return obj;
}, {});
return result;
};
const result = dataSet(data, beginDate, endDate);
// OUTPUT
[ { value: 0, date: '01.08.2019' },
{ value: 12, date: '02.08.2019' },
{ value: 34, date: '03.08.2019' },
{ value: 0, date: '04.08.2019' },
{ value: 65, date: '05.08.2019' },
{ value: 0, date: '06.08.2019' } ]
Upvotes: 0
Views: 235
Reputation: 917
I think the main issue here is that you are using a reduce
function when all you need is a map
function (if I'm understanding your problem correctly). A reduce
function is meant to take an array and reduce it down to one value. A map
function is meant to take an array and transform each and every item in that array to something new. So, you want to map each value of your days
array to either 0 or its value in data
:
const result = days.map(date => {
value = (data.find(element => element.date == date))?.value || 0;
return { value: value, date: date };
});
EDIT: I see that you're having an issue with the above when it's undefined
(not sure why, probably a syntax error on my end as I mentioned in the comment) but that one line shouldn't really matter. I wrote a short, one-liner for filling up value
but if you understood the code I don't think you would still consider yourself "stuck", so let me explain it to you. We have the following line:
value = (data.find(element => element.date == date))?.value || 0;
Where we are trying to either find and use the value in the data
array or, if it does not exist, use 0
. Let's break apart the above line:
data.find(element => element.date == date)
This performs a search on the data
array where it is looking for any item such that the items date
is equal to the date we give it. If it finds it, it returns it. If it does not find it, it returns undefined
. My short-hand code ?.value
, if you read the link I provided, is supposed to test to see if it returned undefined
and if not return the value
of the result. If it did return undefined
, however, the ||
should have used 0
as the value instead. If the short-hand version of this is not working, you can do it in more steps (which is clearer to read):
const result = days.map(date => {
let found = data.find(element => element.date == date);
let value = 0;
if (found) {
value = found.value;
}
return { value: value, date: date };
});
If you don't understand why something is supposed to work when given an answer it's a good idea to ask or investigate instead of just plugging it in and hoping for the best. If it works you definitely want to know why it works, and if it doesn't work it's always helpful to understand why it doesn't so you can keep working toward the correct answer. It's an especially good idea in a place like this where a lot of the time we're not running code and it's easy to make errors :)
JS Bin with working function (and hardcoded data and days): https://jsbin.com/fewupogefe/edit?js,console,output
Upvotes: 1
Reputation: 1712
I think this is what your looking for.
const data = [
{ value: 12, date: '01.01.2019' },
{ value: 34, date: '02.01.2019' },
{ value: 65, date: '03.01.2019' },
{ value: 8, date: '04.01.2019' },
{ value: 30, date: '05.01.2019' },
{ value: 87, date: '06.01.2019' },
];
const findItems = (items, startDate, endDate) => {
return items.filter((item) => {
let dateObject = new Date(item.date);
return dateObject >= startDate && dateObject <= endDate;
})
}
console.log(findItems(data, new Date('03.01.2019'), new Date('05.01.2019')))
Upvotes: 1