learnbydoing
learnbydoing

Reputation: 499

How to filter and map Array in JavaScript

The original array has several objects within it, each of these objects has three properties (timestamp, name and age).

If multiple timestamps in a row are 15 minutes apart, they will be grouped into the same object. Afterwards, a new property called end will be added, which will be the timestamp value of the last element of this group plus 15 minutes.

If there are not several elements in a row with a difference of 15 minutes between them, the end property will have the timestamp plus 15 minutes as a value.

This is my current code:

const data = [
    {
        timestamp: '2021-11-23T14:15:00+0000',
        name: 'John',
        age: 25,
    },
    {
        timestamp: '2021-11-23T14:30:00+0000',
        name: 'John',
        age: 25,
    },
    {
        timestamp: '2021-11-23T14:45:00+0000',
        name: 'John',
        age: 25,
    },
    {
        timestamp: '2021-11-23T15:45:00+0000',
        name: 'John',
        age: 25,
    },
    {
        timestamp: '2021-11-23T14:15:00+0000',
        name: 'Anne',
        age: 32,
    },
    {
        timestamp: '2021-11-23T14:30:00+0000',
        name: 'Anne',
        age: 32,
    },
    {
        timestamp: '2021-11-23T14:45:00+0000',
        name: 'Anne',
        age: 32,
    },
    {
        timestamp: '2021-11-23T15:45:00+0000',
        name: 'Anne',
        age: 32,
    },
]

const newArray = data.reduce((accumulator, current) => {
    const end = new Date(Date.parse(current.timestamp) + 15 * 60 * 1000)
    if (accumulator.length === 0) {
        accumulator.push({
            ...current,
            end,
        })
    } else {
        const last = accumulator[accumulator.length - 1]
        if (last.name === current.name && last.age === current.age) {
            last.end = end
        } else {
            accumulator.push({
                ...current,
                end,
            })
        }
    }
    return accumulator
}, [])

console.log(newArray)

However the end result of my code is not exactly what I want. I would like my result to be like this:

[
    {
        timestamp: '2021-11-23T14:15:00+0000',
        name: 'John',
        age: 25,
        end: '2021-11-23T15:00:00+0000'
    },
    {
        timestamp: '2021-11-23T15:45:00+0000',
        name: 'John',
        age: 25,
        end: '2021-11-23T16:00:00+0000'
    },
    {
        timestamp: '2021-11-23T14:15:00+0000',
        name: 'Anne',
        age: 32,
        end: '2021-11-23T15:00:00+0000'
    },
    {
        timestamp: '2021-11-23T15:45:00+0000',
        name: 'Anne',
        age: 32,
        end: '2021-11-23T16:00:00+0000'
    }
]

Upvotes: 2

Views: 184

Answers (2)

Terry Lennox
Terry Lennox

Reputation: 30675

You can use Array.reduce() to get the required result as in your own code, but we can make a slight change to update the lastItem in the accumulator array if

  • The names are the same (lastItem.name === name)
  • The dates are within 15 minutes

If this condition isn't met we simply add to the accumulator array.

const data = [ { timestamp: '2021-11-23T14:15:00+0000', name: 'John', age: 25, }, { timestamp: '2021-11-23T14:30:00+0000', name: 'John', age: 25, }, { timestamp: '2021-11-23T14:45:00+0000', name: 'John', age: 25, }, { timestamp: '2021-11-23T15:45:00+0000', name: 'John', age: 25, }, { timestamp: '2021-11-23T14:15:00+0000', name: 'Anne', age: 32, }, { timestamp: '2021-11-23T14:30:00+0000', name: 'Anne', age: 32, }, { timestamp: '2021-11-23T14:45:00+0000', name: 'Anne', age: 32, }, { timestamp: '2021-11-23T15:45:00+0000', name: 'Anne', age: 32, }, ] 
    
const result = data.reduce((acc, { timestamp, name, age }) => { 
    let lastItem = acc[acc.length - 1];
    let end = new Date(Date.parse(timestamp) + 15*60*1000);
    
    // If the current row matches just update the end time
    if (lastItem && lastItem.name === name && (Date.parse(lastItem.end) - Date.parse(timestamp) >= 0)) { 
        lastItem.end = end;
    } else {
        acc.push({ timestamp, name, age, end });
    } 
    return acc;
}, [])

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

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386560

You could search for the last interval and update end if found. Otherwise add a new object.

const data = [{ timestamp: '2021-11-23T14:15:00+0000', name: 'John', age: 25 }, { timestamp: '2021-11-23T14:30:00+0000', name: 'John', age: 25 }, { timestamp: '2021-11-23T14:45:00+0000', name: 'John', age: 25 }, { timestamp: '2021-11-23T15:45:00+0000', name: 'John', age: 25 }, { timestamp: '2021-11-23T14:15:00+0000', name: 'Anne', age: 32 }, { timestamp: '2021-11-23T14:30:00+0000', name: 'Anne', age: 32 }, { timestamp: '2021-11-23T14:45:00+0000', name: 'Anne', age: 32 }, { timestamp: '2021-11-23T15:45:00+0000', name: 'Anne', age: 32 }]

const newArray = data.reduce((accumulator, current) => {
    const
        end = new Date(Date.parse(current.timestamp) + 15 * 60 * 1000).toISOString(),
        item = accumulator.find(o =>
            o.name === current.name &&
            o.end === new Date(current.timestamp).toISOString()
        );
    
    if (item) item.end = end;
    else accumulator.push({ ...current, end });

    return accumulator;
}, [])

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

Upvotes: 2

Related Questions