Xuhang
Xuhang

Reputation: 495

How can I remove duplicate member from array of objects based on object property values?

The array looks like:

var test = [
           {
            Time: new Date(1000), 
            psi:100.0
           }, 
           {
            Time: new Date(1000), 
            psi:200.0
           }, 
           {
            Time: new Date(2000), 
            psi:200.0
           }
          ]

The function looks like (the function was copied from some online resource, couldn't find the exact reference.)

function uniqTimetable(nums){
  console.log(nums); //log#1
  var length = nums.length;
  var count = 0;
  for (var i =0; i< length-1; i++){
    if (nums[count].Time.getTime() !== nums[i+1].Time.getTime()){
      count ++;
      nums[count] = nums[i+1];
    }
  }
  nums.length = count + 1;
  console.log(nums); // log #2
}

uniqTimetable(test);
console.log(test);// log #3 

Are there any problems of

With electron/node.js, the output looks a bit weird.

In log#1, it shows the array length is 2 instead of 3. Something seems wrong with the function. Any suggestions welcome.

Thanks in advance.

Upvotes: 0

Views: 62

Answers (3)

Carsten Massmann
Carsten Massmann

Reputation: 28196

I like @Akin's answer! But unfortunately the .indexOf() function does not work for Date objects with the same value, since each object is still considered to be different and the .indexOf() function will always find the index of the Date object itself and never another "copy". To overcome this I convert the Date object back to milliseconds before collecting the values in an array (tst). I do this with myArr.map(mapObj => mapObj[prop].getTime()) before I go into the .filter function.

As the .getTime() method will only work for Date objects it does not make sense to keep the property prop as an argument. Instead I hardcoded the .Time property into the code.

Edit:

By coercing a numerical data type with a unary operator + for the .Time property I can leave out the .getTime() method which will be applied implicitly.

var test = [{Time: new Date(1000), psi:100.0}, 
            {Time: new Date(1000), psi:200.0}, 
            {Time: new Date(2000), psi:200.0}];

function Cars10m_remDups(myArr) {
  let tst=myArr.map(o=>+o.Time);
  return myArr.filter((o, i)=>tst.indexOf(+o.Time)===i);
}
// for comparison: --> will list all three objects!
function Akin_remDups(myArr, prop) {
  return myArr.filter((obj, pos, arr) => {
   return arr.map(mapObj => mapObj[prop]).indexOf(obj[prop]) === pos;
  });
}
// Zero's one-liner works too, here: my shortened version
const Zero_remDups = myArr => myArr.filter(({Time}, i, array) => 
  !array.find((item, j) => +item.Time-Time==0&&i>j));
// also: with "i>j" I pick the first unique (Zero chose the last)


console.log('Cars10m:',Cars10m_remDups(test));
console.log('Akin:',Akin_remDups(test,"Time"));
console.log('Zero:',Zero_remDups(test));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

ZER0
ZER0

Reputation: 25322

If I understood the problem, you can solve it in one line function:

const test = [{
    Time: new Date(1000),
    psi: 100.0
  },
  {
    Time: new Date(1000),
    psi: 200.0
  },
  {
    Time: new Date(2000),
    psi: 200.0
  }
]

const unique = test.filter(({Time}, i, array) => 
  !array.find((item, j) => item.Time.getTime() === Time.getTime() && j > i));

console.log(unique);

(I assumed psi is not relevant)

It uses find and filter array's methods.

Upvotes: 2

Akin Okegbile
Akin Okegbile

Reputation: 1176

function removeDuplicates(myArr, prop) {
    return myArr.filter((obj, pos, arr) => {
        return arr.map(mapObj => mapObj[prop]).indexOf(obj[prop]) === pos;
    });
}
removeDuplicates(test,"Time")

Using the filter function of javascript, to return the List of only unique elements.

Upvotes: 1

Related Questions