Фильтровать массив объектов с одинаковыми значениями периода на основе предпоследней метки времени (даты)?

#javascript #arrays #algorithm

#javascript #массивы #алгоритм

Вопрос:

Я хочу отфильтровать массив, объект, который содержит предпоследнюю дату за тот же период. Например, для "period": 2 . "timestamp": "3/11/2016 02:15:11" будет ли предпоследняя дата.

Входной массив:

 [ 
  { "ip": "11.11.11.11", "timestamp": "3/11/2016 02:13:11", "amount": 7.25, "period": 2 },
  { "ip": "11.11.11.11", "timestamp": "3/11/2016 02:15:11", "amount": 7.25, "period": 2 },
  { "ip": "11.11.11.11", "timestamp": "3/11/2016 06:50:57", "amount": 11.75, "period": 6 },
  { "ip": "11.11.11.11", "timestamp": "3/11/2016 06:52:45", "amount": 11.75, "period": 6 }
  { "ip": "11.11.11.11", "timestamp": "3/11/2016 06:59:59", "amount": 11.75, "period": 6 },
  { "ip": "11.11.11.11", "timestamp": "3/11/2016 07:02:54", "amount": 4.5, "period": 7 }
]
 

Ожидаемый выходной массив:

 [ 
  { "ip": "11.11.11.11", "timestamp": "3/11/2016 02:13:11", "amount": 7.25, "period": 2 },  
  { "ip": "11.11.11.11", "timestamp": "3/11/2016 06:52:45", "amount": 11.75, "period": 6 },
  { "ip": "11.11.11.11", "timestamp": "3/11/2016 07:02:54", "amount": 4.5, "period": 7 }
]
 

Ответ №1:

Вот решение, которое sort() сортирует все элементы по дате, затем reduce() сортирует их по периоду и map() в результате Object.values() возвращает второй элемент или первый, если есть только один.

 const input = [ 
  { "ip": "11.11.11.11", "timestamp": "3/11/2016 02:15:11", "amount": 7.25, "period": 2 },
  { "ip": "11.11.11.11", "timestamp": "3/11/2016 02:13:11", "amount": 7.25, "period": 2 },
  { "ip": "11.11.11.11", "timestamp": "3/11/2016 06:50:57", "amount": 11.75, "period": 6 },
  { "ip": "11.11.11.11", "timestamp": "3/11/2016 06:52:45", "amount": 11.75, "period": 6 },
  { "ip": "11.11.11.11", "timestamp": "3/11/2016 06:59:59", "amount": 11.75, "period": 6 },
  { "ip": "11.11.11.11", "timestamp": "3/11/2016 07:02:54", "amount": 4.5, "period": 7 }
]

// sort by timestamp
input.sort(function(a,b){
  return new Date(b.timestamp) - new Date(a.timestamp);
});

const filtered = Object.values(input
    // reduce by period
      .reduce((acc, o) => 
        (acc[o.period] = [...acc[o.period] ?? [], { ...o }], acc), {}))
    // map and return the second element if it exists, otherwise the first.
      .map((v) => v[1] ?? v[0]);


console.log(filtered); 

Ответ №2:

Это работает для вас?

 let arr =[ 
    { "ip": "11.11.11.11", "timestamp": "3/11/2016 02:13:11", "amount": 7.25, "period": 2 },
    { "ip": "11.11.11.11", "timestamp": "3/11/2016 02:15:11", "amount": 7.25, "period": 2 },
    { "ip": "11.11.11.11", "timestamp": "3/11/2016 06:50:57", "amount": 11.75, "period": 6 },
    { "ip": "11.11.11.11", "timestamp": "3/11/2016 06:52:45", "amount": 11.75, "period": 6 },
    { "ip": "11.11.11.11", "timestamp": "3/11/2016 06:59:59", "amount": 11.75, "period": 6 },
    { "ip": "11.11.11.11", "timestamp": "3/11/2016 07:02:54", "amount": 4.5, "period": 7 }
  ]

  let orederedByPeriod = {};

  arr.forEach(v => {
    if(orederedByPeriod[v.period]){
        orederedByPeriod[v.period].push({...v});
    } else{
        orederedByPeriod[v.period] = [{...v}];
    }
  });

  let response = [];

  for(let key in orederedByPeriod){
      if(orederedByPeriod[key].length === 1){
        response.push(orederedByPeriod[key][0]);
      } else{
        orederedByPeriod[key].sort((a, b) => new Date(a.timestamp) > new Date(b.timestamp) ? 1 : -1);
        response.push(orederedByPeriod[key][orederedByPeriod[key].length -2]);
      }
  }

  console.log(response);