Home > Mobile >  How to filter and map Array in JavaScript
How to filter and map Array in JavaScript

Time:11-24

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)
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

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'
    }
]

CodePudding user response:

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; }
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

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; }
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related