【问题标题】:Filter array based of two conditions基于两个条件的过滤器数组
【发布时间】:2016-06-08 10:37:00
【问题描述】:

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

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. 唯一 ID(条目 1 和 3 仅存在一次)
  2. timestemp(只添加最后一个timestemp的对象)

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

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

【问题讨论】:

  • "我尝试使用 array.filter 来做,但没有成功" - 所以向我们展示失败的尝试,告诉我们它是如何出错的,告诉我们任何错误生成(在开发人员控制台中可见,在大多数浏览器中为 F12),解释它做了什么以及你希望它做什么。这样,您下次可能会学到一些有用的东西,其他人也可能会学到一些重要或有趣的东西。

标签: javascript arrays object javascript-objects lodash


【解决方案1】:

您可以使用orderBy()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>

【讨论】:

    【解决方案2】:

    首先,您将时间戳拼写为 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/
    如果这是您想要的答案,请务必按upvote 和greentick。

    【讨论】:

      【解决方案3】:

      由于需要使用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 的项目。为firstArr 中的每个元素传递state。因为结果是一个对象(id's 作为键,实际项作为值),所以我们需要将map 返回一个数组。

      【讨论】:

        【解决方案4】:

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

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

        var found = [];
        firstArr.reverse().filter( function(el){
        
          if( found.indexOf( el.id ) === -1 ){
            found.push( el.id );
            return true;
          }
          return false;
        
        }).reverse();
        

        【讨论】:

          【解决方案5】:

          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/

          【讨论】:

            【解决方案6】:

            您可以对出现的第一个 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 );
            &lt;pre id=output&gt;

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2023-03-04
              • 1970-01-01
              • 2010-10-22
              • 2014-02-20
              • 2019-10-28
              • 2021-11-21
              • 2021-09-28
              相关资源
              最近更新 更多