查找具有多次匹配属性的JSON对象

时间:2016-07-04 18:09:25

标签: javascript angularjs json underscore.js

我需要找到具有相同名称属性的json数组中的每个元素,例如此处Alaska是两次,然后我需要比较两个对象的lastupdate并选择具有最新更新时间的对象。从stackoverflow中的答案中采用(抱歉,我丢失了链接)我可以删除具有相同名称属性的对象但是如何保留具有最新更新时间的对象?

[{
    "name": "Alaska",
    "Republican_fre": 3,
    "Democrats_fre": 0,
    "winner": "R",
    "iso_2": "AK",
    "electoral_vote": 3,
    "totalComponents": 3,
    "date": "29.06.2016",
    "lastupdate": "1467233426"
}, {
    "name": "Alabama",
    "Republican_fre": 3,
    "Democrats_fre": 0,
    "winner": "R",
    "iso_2": "AL",
    "electoral_vote": 9,
    "totalComponents": 3,
    "date": "29.06.2016",
    "lastupdate": "1467233426"
}, {
    "name": "Arkansas",
    "Republican_fre": 2,
    "Democrats_fre": 0,
    "winner": "R",
    "iso_2": "AR",
    "electoral_vote": 6,
    "totalComponents": 2,
    "date": "29.06.2016",
    "lastupdate": "1467233426"
},
{
    "name": "Alaska",
    "Republican_fre": 5,
    "Democrats_fre": 0,
    "winner": "R",
    "iso_2": "AK",
    "electoral_vote": 3,
    "totalComponents": 5,
    "date": "29.06.2016",
    "lastupdate": "1467282133"                 
}]

代码:

function arrUnique(arr) {
    var cleaned = [];
    data.forEach(function(itm) {
        var unique = true;
        cleaned.forEach(function(itm2) {
         var minValue = Math.min(itm.lastupdate, itm2.lastupdate)
            if (_.isEqual(itm.name, itm2.name)){
            unique = false;
            } 
        });
        if (unique)  cleaned.push(itm);
    });
    return cleaned;
}

var uniqueStandards = arrUnique(data);

jsfiddle:

预期输出 预期的输出是它保持Alsaka对象之一最新' lastupdate'值。因此,它首先检查具有相同名称属性的对象,然后比较lastupdate值并保留具有最新值的对象

5 个答案:

答案 0 :(得分:5)

您可以使用下划线sortBy()按照lastupdatereverse()对集合中的项目进行排序,以便lastupdate按降序排序所有项目订购,然后使用uniq()仅保留唯一的name项。

var uniqueStandards = _.uniq(_.sortBy(data, 'lastupdate').reverse(), 'name');



var data = [{
  "name": "Alaska",
  "Republican_fre": 3,
  "Democrats_fre": 0,
  "winner": "R",
  "iso_2": "AK",
  "electoral_vote": 3,
  "totalComponents": 3,
  "date": "29.06.2016",
  "lastupdate": "1467233426"
}, {
  "name": "Alabama",
  "Republican_fre": 3,
  "Democrats_fre": 0,
  "winner": "R",
  "iso_2": "AL",
  "electoral_vote": 9,
  "totalComponents": 3,
  "date": "29.06.2016",
  "lastupdate": "1467233426"
}, {
  "name": "Arkansas",
  "Republican_fre": 2,
  "Democrats_fre": 0,
  "winner": "R",
  "iso_2": "AR",
  "electoral_vote": 6,
  "totalComponents": 2,
  "date": "29.06.2016",
  "lastupdate": "1467233426"
}, {
  "name": "Alaska",
  "Republican_fre": 5,
  "Democrats_fre": 0,
  "winner": "R",
  "iso_2": "AK",
  "electoral_vote": 3,
  "totalComponents": 5,
  "date": "29.06.2016",
  "lastupdate": "1467282133"
}];

var uniqueStandards = _.uniq(_.sortBy(data, 'lastupdate').reverse(), 'name');

document.body.innerHTML = '<pre>' + JSON.stringify(uniqueStandards, 0, 4) + '</pre>';
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
&#13;
&#13;
&#13;

一个香草JS解决方案将是:

var uniqueStandards = data
.slice() // this makes sure that we're not mutating the original array
.sort(function(x, y) { return y.lastupdate - x.lastupdate; }) // sort in descending order
.filter(function(x) {  // this ensure items with unique names
  return (this[x.name]? false: (this[x.name] = true));
}, {});

&#13;
&#13;
var data = [{
  "name": "Alaska",
  "Republican_fre": 3,
  "Democrats_fre": 0,
  "winner": "R",
  "iso_2": "AK",
  "electoral_vote": 3,
  "totalComponents": 3,
  "date": "29.06.2016",
  "lastupdate": "1467233426"
}, {
  "name": "Alabama",
  "Republican_fre": 3,
  "Democrats_fre": 0,
  "winner": "R",
  "iso_2": "AL",
  "electoral_vote": 9,
  "totalComponents": 3,
  "date": "29.06.2016",
  "lastupdate": "1467233426"
}, {
  "name": "Arkansas",
  "Republican_fre": 2,
  "Democrats_fre": 0,
  "winner": "R",
  "iso_2": "AR",
  "electoral_vote": 6,
  "totalComponents": 2,
  "date": "29.06.2016",
  "lastupdate": "1467233426"
}, {
  "name": "Alaska",
  "Republican_fre": 5,
  "Democrats_fre": 0,
  "winner": "R",
  "iso_2": "AK",
  "electoral_vote": 3,
  "totalComponents": 5,
  "date": "29.06.2016",
  "lastupdate": "1467282133"
}];

var uniqueStandards = data
.slice() // this makes sure that we're not mutating the original array
.sort(function(x, y) { return y.lastupdate - x.lastupdate; }) // sort in descending order
.filter(function(x) {  // this ensure items with unique names
  return (this[x.name]? false: (this[x.name] = true));
}, {});

document.body.innerHTML = '<pre>' + JSON.stringify(uniqueStandards, 0, 4) + '</pre>';
&#13;
&#13;
&#13;

或者,您可以尝试lodash

var uniqueStandards = _(data).orderBy('lastupdate', 'desc').uniqBy('name').value();

上面的snipet使用orderBy()lastupdate降序排序,uniqBy()确保集合只有唯一名称。

&#13;
&#13;
var data = [{
  "name": "Alaska",
  "Republican_fre": 3,
  "Democrats_fre": 0,
  "winner": "R",
  "iso_2": "AK",
  "electoral_vote": 3,
  "totalComponents": 3,
  "date": "29.06.2016",
  "lastupdate": "1467233426"
}, {
  "name": "Alabama",
  "Republican_fre": 3,
  "Democrats_fre": 0,
  "winner": "R",
  "iso_2": "AL",
  "electoral_vote": 9,
  "totalComponents": 3,
  "date": "29.06.2016",
  "lastupdate": "1467233426"
}, {
  "name": "Arkansas",
  "Republican_fre": 2,
  "Democrats_fre": 0,
  "winner": "R",
  "iso_2": "AR",
  "electoral_vote": 6,
  "totalComponents": 2,
  "date": "29.06.2016",
  "lastupdate": "1467233426"
}, {
  "name": "Alaska",
  "Republican_fre": 5,
  "Democrats_fre": 0,
  "winner": "R",
  "iso_2": "AK",
  "electoral_vote": 3,
  "totalComponents": 5,
  "date": "29.06.2016",
  "lastupdate": "1467282133"
}];

var uniqueStandards = _(data).orderBy('lastupdate', 'desc').uniqBy('name').value();

document.body.innerHTML = '<pre>' + JSON.stringify(uniqueStandards, 0, 4) + '</pre>';
&#13;
<script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.min.js"></script>
&#13;
&#13;
&#13;

答案 1 :(得分:4)

这是一种方法。使用name作为键创建对象,并基于lastUpdate更新对象,然后将对象映射到数组

function arrUnique(arr){
   var tmp={};
   arr.forEach(function(item) {
      if(!tmp[item.name] || +item.lastupdate > +tmp[item.name].lastupdate){         
           tmp[item.name] = item ;        
       }
   });
   return Object.keys(tmp).map(function(key){
      return tmp[key]
   });
}

请注意,lastUpdate的字符串比较可能无法返回正确的结果,这就是我转换为数字的原因

DEMO

答案 2 :(得分:3)

我希望我能正确理解你。

您希望获得由max(lastupdate)排序的不同值的输出数组。

这段代码按照我的描述工作。它称为数组分组

var group = [];
arr.forEach(function(val, key)
    {
        if(!group[val.name])
            group[val.name] = val;
        else{
            if(group[val.name].lastupdate < val.lastupdate)
                group[val.name] = val;
        }
    }
);
console.log(group);

答案 3 :(得分:3)

我严重怀疑JSON是应用该操作的最佳格式。

如果你真的需要使用JSON,那么最好在输入时检查它,并覆盖属性(或只是日期)。在这种情况下,您可以确保不存在重复。

如果您在字符串中有任意值并且搜索了重复项,则这是一项非常棘手的任务。显而易见的解决方案是订购它然后在O(nlogn)时间搜索欺骗。如果我们使用哈希,问题可以在O(n)复杂度中解决。

但是要知道你有一个已知数量的状态,你应该为每个状态迭代数组。

foreach state in states
    var choosenOne = {}
    foreach item in array
        if(choosenOne == {}) {
            choosenOne = item;
        } else {
            if(item.name == state) {
                if(choosenOne.lastupdate > item.lastupdate)
                    delete item;
            } else {
                delete choosenOne
                choosenOne = item;
            }
        }

这只是应该为你提供O(50 * n)~O(n)

的解决方案的算法

答案 4 :(得分:3)

以下是使用forEachmap的简单javascript解决方案,以检查索引并使用lastupdate更新新对象。

&#13;
&#13;
var data = [{"name":"Alaska","Republican_fre":3,"Democrats_fre":0,"winner":"R","iso_2":"AK","electoral_vote":3,"totalComponents":3,"date":"29.06.2016","lastupdate":"1467233426"},{"name":"Alabama","Republican_fre":3,"Democrats_fre":0,"winner":"R","iso_2":"AL","electoral_vote":9,"totalComponents":3,"date":"29.06.2016","lastupdate":"1467233426"},{"name":"Arkansas","Republican_fre":2,"Democrats_fre":0,"winner":"R","iso_2":"AR","electoral_vote":6,"totalComponents":2,"date":"29.06.2016","lastupdate":"1467233426"},{"name":"Alaska","Republican_fre":5,"Democrats_fre":0,"winner":"R","iso_2":"AK","electoral_vote":3,"totalComponents":5,"date":"29.06.2016","lastupdate":"1467282133"}]
var result = [];

data.forEach(function(e) {
  if(!this[e.name]) {
    this[e.name] = e;
     result.push(e);
  } else {
    var index = result.map(function(a) { return a.name}).indexOf(e.name);
    if(e.lastupdate > result[index].lastupdate) result[index] = e;
  }
}, {});

console.log(result)
&#13;
&#13;
&#13;