基于两个条件过滤数组

Filter array based of two conditions

我有以下对象数组,(据说这里的时间是模拟的,更大的是最后一个)

var firstArr = [{
  id: 1,
  a: 2,
  timestemp: 111
}, {
  id: 2,
  a: 4,
  timestemp: 222
}, {
  id: 3,
  a: 6,
  timestemp: 333
}, {
  id: 1,
  a: 3,
  timestemp: 777
}, {
  id: 3,
  a: 5555,
  timestemp: 5555
}];

我需要做的是以某种方式过滤这个数组并创建具有唯一值的新数组。

最后我需要

var endArr = [{
  id: 1,
  a: 3,
  timestemp: 777
}, {
  id: 2,
  a: 4,
  timestemp: 222
},  {
  id: 3,
  a: 5555,
  timestemp: 555
}];

如您所见,我已通过两件事过滤此数组

  1. uniqe ID (the entry 1 & 3 are exist just once)
  2. timestemp (add just the object with the last timestemp)

如何使用 map/reduce/filter 等数组方法来做到这一点?

我尝试用 array.filter 做,但没有成功

首先你把timestamp拼成了timestemp。

var firstArr = [{
  id: 1,
  a: 2,
  timestamp: 111
}, {
  id: 2,
  a: 4,
  timestamp: 222
}, {
  id: 3,
  a: 6,
  timestamp: 333
}, {
  id: 1,
  a: 3,
  timestamp: 777
}, {
  id: 3,
  a: 5555,
  timestamp: 5555
}];

函数如下:

function updateList(a_list) {

    var seen = {};

    for (var entry in a_list) {
        var id = a_list[entry]["id"];

        if (seen.hasOwnProperty(id)) {
            var current_timestamp = seen[id]["timestamp"]
            var check_timestamp = a_list[entry]["timestamp"]

            if (current_timestamp < check_timestamp) {
                 seen[id] = a_list[entry];
            }

        } else {
            seen[id] = a_list[entry];
        }
    }

    var updated = [];
    for (var newest in seen) {
        updated.push(seen[newest]);
    } 
    return updated;
} 

https://jsfiddle.net/vpg3onqm/
如果这是您想要的答案,请务必按赞和绿勾。

由于需要使用 filter/map/reduce,我想我会选择:

var lastestPerId = firstArr.reduce(function(state, curr) {
  if(state[curr.id]){ // We've seen this id before
     if(curr.timestemp > state[curr.id].timestemp) { // and its later
        state[curr.id] = curr; // so, update this item to be the latest item
     }
  } else {
     state[curr.id]  = curr; // add because unknown
  }

  return state; // pass along the state to the next item in the array
}, {});

var endArr = Object.keys(lastestPerId)
    .map(function (key) {return bestPerId[key]});

这将创建一个初始状态 ({}),循环遍历 firstArr 中的每个项目。它会尝试找出 id 是否已知,如果已知,它会跟踪(在 state 中)具有最高 timestemp 的项目。 state 被传递给 firstArr 中的每个元素。因为结果是一个对象(以 id 作为键,实际项目作为值),我们需要 map 将它返回到数组。

如果 firstArr 按时间戳排序,这将起作用。返回的数组也会按时间戳排序。

从数组末尾(较大的时间戳)开始,如果尚未找到当前元素,则将其包含在新数组中。 found 数组用于跟踪提取的元素。

var found = [];
firstArr.reverse().filter( function(el){

  if( found.indexOf( el.id ) === -1 ){
    found.push( el.id );
    return true;
  }
  return false;

}).reverse();

groupBy 是你的好友:https://lodash.com/docs#groupBy

_(firstArr)
  .groupBy('id')
  .map(function(x) {
    return _(x).orderBy(x,['timestemp'], ['desc']).head();
  })
  .value();

https://jsfiddle.net/koljada/53esaqLz/3/

您可以使用 orderBy() and uniqBy() 获取具有最新时间戳的唯一 ID 的所有项目:

var firstArr = [{
  id: 1,
  a: 2,
  timestamp: 111
}, {
  id: 2,
  a: 4,
  timestamp: 222
}, {
  id: 3,
  a: 6,
  timestamp: 333
}, {
  id: 1,
  a: 3,
  timestamp: 777
}, {
  id: 3,
  a: 5555,
  timestamp: 5555
}];

var result = _(firstArr)
.orderBy(['id', 'timestamp'], ['asc', 'desc'])
.uniqBy('id')
.value();

console.log(result);
<script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.min.js"></script>

您可以排序,然后过滤第一个出现的 ID:

var firstArr = [
    { id: 1, a: 2, timestemp: 111 },
    { id: 2, a: 4, timestemp: 222 },
    { id: 3, a: 6, timestemp: 333 },
    { id: 1, a: 3, timestemp: 777 },
    { id: 3, a: 5555, timestemp: 5555 }
];

// sort firstArr by decrescent timestamp:
firstArr.sort((x,y)=>y.timestemp-x.timestemp);

// get only the first occurrence of each id:
var endArr = firstArr.filter((o,i)=>i==firstArr.findIndex(u=>u.id==o.id));

// job finished
output.innerHTML = JSON.stringify( endArr, null, 2 );
<pre id=output>