4
\$\begingroup\$

The question is very simple : I have an array of items, that all have a date. According to the date, I would like to split this array into several arrays.

In my case, I would like to split the array into 3 arrays : one that contains result of the last 24h, the other 48h, then the last one on the week.

Here is a minimal reproduction of the case, with the final solution.

const now = Date.now();
const day = 1000 * 3600 * 24;

const todayTime = now - day;
const yesterdayTime = now - day * 2;
const weekTime = now - day * 7;

const arr = [
  { id: 1, date: todayTime + 100 },
  { id: 2, date: yesterdayTime + 100 },
  { id: 3, date: weekTime + 100 },
];

const today = arr.filter(item => item.date - todayTime > 0);
const yesterday = arr.filter(item => item.date - yesterdayTime > 0 && item.date - todayTime < 0);
const week = arr.filter(item => item.date - weekTime > 0 && item.date - yesterdayTime < 0);

console.log(today, yesterday, week);

Is there a way to make it more concise ? I'm talking about code length : I would like to reduce it to the maximum, especially the definition of the 3 arrays. I tried with reduce, but the syntax is pretty ugly.

Any ideas ?

\$\endgroup\$
0

2 Answers 2

3
\$\begingroup\$

Always create a function

Its not really code if its not a function, you may as well just output the 3 arrays directly. (my personal view on global inline code).

You may say, "This is just an example". No it can not be just an example, a function has special powers and is written differently than inline code. Plus examples are boarder line off topic here, this question may get closed.

Part of a functions power is that it makes you think about how you solve the problem differently from inline code.

Look for change

When you write a function you look for the parts of the logic and data that change. You pass that to the function as arguments. The function uses these argument to process the data and return the desired results.

In this case you have

  • the array of items to split.
  • The number of days old to split the data, eg 1,2,and 7 days.

Thus we can have something like the following. The function is declared inside another so that all it needs is safely encapsulated and outside of unrelated scopes.

const splitByDaysOld = (() => {
    const MS_IN_DAY = 8.64e7;
    const sorter = (a, b) => a - b;
    return function(array, periods) {
        const now = Date.now();
        var start = 0;
        return periods.sort(sorter).map(day => {
            const res = array.filter(item => {
                const daysOld = (item.date - now) / MS_IN_DAY;
                return daysOld >= start && daysOld < day;
            });
            start = day;
            return res;
        });
    };
})();
            

It returns an array of arrays, one for each period.

Example below has 3 periods 0 to < 1, 1 to < 2, and 2 to < 7 days old.

const [today, yesterday, week] = splitByDaysOld(arr, [1, 2, 7]);

Note that the periods array is sorted from most recent to oldest and that the result will be in the same order

\$\endgroup\$
1
  • \$\begingroup\$ The function is called listAllPercos and it exists. So yes, it is just an example. Didn't think about making it like this though. Question totally out of context, but is this considerd a factory ? And I'm going to try to implement it with what I need and don't, and keep you updated. Anyway, have my upvote too ! \$\endgroup\$
    – Maryannah
    Commented Mar 1, 2019 at 14:36
2
\$\begingroup\$

item.date - todayTime > 0 is the same as item.date > todayTime.

Your less-than condition should be less-than-or-equal, otherwise anything falling on a day boundary won't match any category.

const now = Date.now(),
     day = 1000 * 3600 * 24,
     arr = [
            { id: 1, date: now - day + 100 },
            { id: 2, date: now - day*2 + 100 },
            { id: 3, date: now - day*7 + 100 },
           ],
    daysAgo=[ 1, 2, 7 ],
    filtered=daysAgo.map( 
        (days,i) => arr.filter( 
            j => j.date > now-day*days && j.date <= now-day*( i ? daysAgo[i-1] : -1 )        
        ) 
    );

console.log(filtered);

\$\endgroup\$
3
  • \$\begingroup\$ As said on your previous comment, I just wrote that fast and didn't really cared about all that. I was more focused on the array operators \$\endgroup\$
    – Maryannah
    Commented Mar 1, 2019 at 13:34
  • \$\begingroup\$ well you can factor out some of the calculations with an array of days - see my code. It's only a little shorter than your version, but it will scale up to many intervals with hardly any increase in code length. \$\endgroup\$ Commented Mar 1, 2019 at 13:58
  • \$\begingroup\$ I have posted this question on SOF and they made the same statement, to which I replied that my case is very specific and I actually don't need genericity, because the data that is one week old gets deleted. I have and will always have 3 arrays, so I don't need to make it generic at all. But your answer is nicely thought indeed, so have my upvote ! \$\endgroup\$
    – Maryannah
    Commented Mar 1, 2019 at 14:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.