Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find a JSON object with property matched more than once

I need to find every element in the json array with same name property for example here Alaska is two times then I need to compare the lastupdate of both of the objects and choose the one with latest update time. Adopting from an answer in stackoverflow (sorry I lost the link) I can remove the object with same name property but how can I keep the one with latest update time?

[{
    "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"                 
}]

code:

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:

Expected Output The expected output is that it keeps the one of the Alsaka objects with lastest 'lastupdate' value. So it first checks for the objects with same name property then compares the lastupdate value and keeps the one with latest value

like image 678
Imo Avatar asked Jul 04 '16 18:07

Imo


People also ask

What is an example of a JSON object?

Example. { "name":"John", "age":30, "car":null } JSON objects are surrounded by curly braces {}. JSON objects are written in key/value pairs. Keys must be strings, and values must be a valid JSON data type (string, number, object, array, boolean or null). Keys and values are separated by a colon.

Why is each key/value pair separated by a comma in JSON?

Each key/value pair is separated by a comma. It is a common mistake to call a JSON object literal "a JSON object". JSON cannot be an object. JSON is a string format.

How do you separate keys and values in a JSON object?

Keys and values are separated by a colon. Each key/value pair is separated by a comma. Values in a JSON object can be another JSON object. You can access nested JSON objects by using the dot notation or bracket notation:

How to check if two objects have the same data?

Comparing two objects like this results in false even if they have the same data. It is because those are two different object instances, they are referring to two different objects. There is no direct method in javascript to check whether two objects have the same data or not.


4 Answers

You can use underscore's sortBy() to sort items in the collection by their lastupdate key, reverse() to have all the items ordered by lastupdate in descending order, and then use uniq() to only preserve unique name items.

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>';
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

A vanilla JS solution would be:

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));
}, {});

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>';

Alternatively, you could give lodash a try:

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

The snipet above uses orderBy() to order the collection by lastupdate in descending order, and uniqBy() to make sure that the collection only has unique names.

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>';
<script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.min.js"></script>
like image 85
ryeballar Avatar answered Oct 09 '22 22:10

ryeballar


Here's one approach. Create object using name as keys and update object based on lastUpdate, then map object to array

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]
   });
}

Note that string comparisons of your lastUpdate may not return correct results which is why I cast to number

DEMO

like image 34
charlietfl Avatar answered Oct 10 '22 00:10

charlietfl


I hope I understand you correctly.

You want to get the output arrayof distinct values ordered by max(lastupdate).

This code works as I described.It called grouping of arrays

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);
like image 44
Vanya Avchyan Avatar answered Oct 09 '22 23:10

Vanya Avchyan


I seriously doubt that JSON is the best format to apply that operation to.

If you really need to use JSON than it is for the best to check that on input, and to overwrite attribute (or just the date). In that case you could make sure that no duplicate exists.

If you had arbitrary values in strings and you searched for duplicates this is a really tricky task. The obvious solution would be to order it and then search for dupes in O(nlogn) time. If we use hash that problem can be solved in O(n) complexity.

But knowing that you have a known number of states you should iterate trough array for each state.

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;
            }
        }

This is just the algorithm that should provide you a solution in O(50*n) ~ O(n)

like image 29
Rouz Avatar answered Oct 09 '22 22:10

Rouz