Home > Net >  Filter array based on other values in that same array
Filter array based on other values in that same array

Time:10-07

I have an array of data like so:

[
   {id: 1, date: "2022-10-01T12:00:00.00", type: 1},
   {id: 2, date: "2022-10-02T12:00:00.00", type: 1},
   {id: 3, date: "2022-10-03T12:00:00.00", type: 2},
   {id: 4, date: "2022-10-04T12:00:00.00", type: 2},
]

I'd like to filter this so that I get an array of objects that only includes objects with the most recent date for each type. So something like this:

[
   {id: 2, dttm: "2022-10-02T12:00:00.00", type: 1},
   {id: 4, dttm: "2022-10-04T12:00:00.00", type: 2},
]

I suspect there's a clever way to do this with the .reduce() function, but I haven't quite figured that out yet.

CodePudding user response:

It's easy to compare dates this way just using string comparing since they are sorted by year-month-date. As for the rest, yes reduce is an option but basically it's just a loop over the array grouping by type.

var arr = [
   {id: 1, date: "2022-10-01T12:00:00.00", type: 1},
   {id: 2, date: "2022-10-02T12:00:00.00", type: 1},
   {id: 3, date: "2022-10-03T12:00:00.00", type: 2},
   {id: 4, date: "2022-10-04T12:00:00.00", type: 2},
];

var grouped = arr.reduce(function(agg, item) {
  agg[item.type] = agg[item.type] || {
    id: item.id,
    dttm: item.date,
    type: item.type
  };
  
  if (item.date > agg[item.type].dttm) {
    agg[item.type].id = item.id
    agg[item.type].dttm  = item.date
  }
  
  return agg;
}, {})

console.log (Object.values(grouped))

CodePudding user response:

We can achieve this using .reduce by keeping a running tally of the most recent items.

Note:

Dates can be compared in js as their valueOf method is equivalent to someDate.getTime() which gives a nice integer for comparison.

let items = [{
    id: 1,
    date: "2022-10-01T12:00:00.00",
    type: 1
  },
  {
    id: 2,
    date: "2022-10-02T12:00:00.00",
    type: 1
  },
  {
    id: 3,
    date: "2022-10-03T12:00:00.00",
    type: 2
  },
  {
    id: 4,
    date: "2022-10-04T12:00:00.00",
    type: 2
  },
]

let recentItems = Object.values(items.reduce((recent, item) => {
  debugger;
  if (
    // type has not items yet
    !recent[item.type]
    // the current item is more recent
    ||
    new Date(recent[item.type].date) < new Date(item.date)
  ) {
    recent[item.type] = item
  }
  return recent;

}, {}))

console.log(recentItems)

CodePudding user response:

This does what you specify. (See in-code comments for more info.)

// Calls filter function on the data array and prints output
const data = getData();
console.log(recentOfEachType(data));

// Defines filter function
function recentOfEachType(arr){

  // Sets up output array
  let recents = [];

  // Loops through data to populate output
  for(const item of arr){

    // Gets position of existing item with this type
    const typeIndex = recents.findIndex(recent => recent.type === item.type);

    // If no item with this type has been added yet
    if(typeIndex < 0){
      recents.push(item);
    }

    // If a newer item is found (ignoring items with identical timestamps)
    else if(item.date > recents[typeIndex].date){      
      recents[typeIndex] = item;
    }
    // (else do nothing)
  }
  return recents;
}

// Creates oringal data array
function getData(){
    return [
       {id: 1, date: "2022-10-01T12:00:00.00", type: 1},
       {id: 2, date: "2022-10-02T12:00:00.00", type: 1},
       {id: 3, date: "2022-10-03T12:00:00.00", type: 2},
       {id: 4, date: "2022-10-04T12:00:00.00", type: 2}
    ];
}

  • Related