arevilla009
arevilla009

Reputation: 453

Remove duplicates from array of objects by 2 matching properties

I'm trying to delete duplicate elements from a dictionary when the key values "hour_from" and "hour_to" are the same. I'm using a double for (I don't remember other less cost algorithms to do it) but I'm having problems with index values.

var hours_array = [
{day: "Mon", hour_from: "00:00", hour_to: "00:00"},
{day: "Mon", hour_from: "00:00", hour_to: "00:16"},
{day: "Mon", hour_from: "00:00", hour_to: "00:16"},
{day: "Thu", hour_from: "00:00", hour_to: "00:25"},
{day: "Mon", hour_from: "00:00", hour_to: "00:33"},
{day: "Fri", hour_from: "00:00", hour_to: "00:83"},
{day: "Sat", hour_from: "02:00", hour_to: "05:33"},
{day: "Thu", hour_from: "02:00", hour_to: "05:33"},
{day: "Wed", hour_from: "12:00", hour_to: "14:00"},
{day: "Sun", hour_from: "22:25", hour_to: "13:45"}]

for (let i=0; i< hours_array.length; i++){
 for (let j=0; j<=hours_array.length; j++){
  if ((hours_array[i]['hour_from'] == hours_array[j]['hour_from']) && (hours_array[i]['hour_to'] == hours_array[j]['hour_to'])){
  delete hours_array[j];
  }
 }
}

I thought it is an error with index values:

enter image description here

Edit: Needed result:

var hours_array = [
{day: "Mon", hour_from: "00:00", hour_to: "00:00"},
{day: "Mon", hour_from: "00:00", hour_to: "00:16"},
{day: "Thu", hour_from: "00:00", hour_to: "00:25"},
{day: "Mon", hour_from: "00:00", hour_to: "00:33"},
{day: "Fri", hour_from: "00:00", hour_to: "00:83"},
{day: "Sat", hour_from: "02:00", hour_to: "05:33"},
{day: "Wed", hour_from: "12:00", hour_to: "14:00"},
{day: "Sun", hour_from: "22:25", hour_to: "13:45"}]

Any suggestion? Any some more efficient algorithm? Thanks for reading!

Upvotes: 0

Views: 74

Answers (4)

Yevhen Horbunkov
Yevhen Horbunkov

Reputation: 15530

You may go lazy way with Array.prototype.reduce() along with Array.prototype.find().

const src = [{day:"Mon",hour_from:"00:00",hour_to:"00:00"},{day:"Mon",hour_from:"00:00",hour_to:"00:16"},{day:"Mon",hour_from:"00:00",hour_to:"00:16"},{day:"Thu",hour_from:"00:00",hour_to:"00:25"},{day:"Mon",hour_from:"00:00",hour_to:"00:33"},{day:"Fri",hour_from:"00:00",hour_to:"00:83"},{day:"Sat",hour_from:"02:00",hour_to:"05:33"},{day:"Thu",hour_from:"02:00",hour_to:"05:33"},{day:"Wed",hour_from:"12:00",hour_to:"14:00"},{day:"Sun",hour_from:"22:25",hour_to:"13:45"}],
      dedupe = src.reduce((res, item) => 
        (
          !res.find(({hour_from, hour_to}) => 
            hour_from == item.hour_from && hour_to == item.hour_to) ? 
          res.push(item) : 
          true, res
        ), [])
      
console.log(dedupe)

Upvotes: 1

Siva Kondapi Venkata
Siva Kondapi Venkata

Reputation: 11001

Use reduce method with combining Object.values.

var hours_array = [
  { day: "Mon", hour_from: "00:00", hour_to: "00:00" },
  { day: "Mon", hour_from: "00:00", hour_to: "00:16" },
  { day: "Mon", hour_from: "00:00", hour_to: "00:16" },
  { day: "Thu", hour_from: "00:00", hour_to: "00:25" },
  { day: "Mon", hour_from: "00:00", hour_to: "00:33" },
  { day: "Fri", hour_from: "00:00", hour_to: "00:83" },
  { day: "Sat", hour_from: "02:00", hour_to: "05:33" },
  { day: "Thu", hour_from: "02:00", hour_to: "05:33" },
  { day: "Wed", hour_from: "12:00", hour_to: "14:00" },
  { day: "Sun", hour_from: "22:25", hour_to: "13:45" }
];

const updated = Object.values(
  hours_array.reduce(
    (acc, curr) => ({
      ...acc,
      [`${curr.hour_from}-${curr.hour_to}`]: { ...curr }
    }),
    {}
  )
);

console.log(updated);

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386654

You could filter the array with the help of a Set.

If a hash value (build from hour_from and hour_to) is in the set, the item is filtered out. If not, then the hash is taken to the set and the item is used.

var getKey = ({ hour_from, hour_to }) => [hour_from, hour_to].join('|'),
    hours_array = [{ day: "Mon", hour_from: "00:00", hour_to: "00:00" }, { day: "Mon", hour_from: "00:00", hour_to: "00:16" }, { day: "Mon", hour_from: "00:00", hour_to: "00:16" }, { day: "Thu", hour_from: "00:00", hour_to: "00:25" }, { day: "Mon", hour_from: "00:00", hour_to: "00:33" }, { day: "Fri", hour_from: "00:00", hour_to: "00:83" }, { day: "Sat", hour_from: "02:00", hour_to: "05:33" }, { day: "Thu", hour_from: "02:00", hour_to: "05:33" }, { day: "Wed", hour_from: "12:00", hour_to: "14:00" }, { day: "Sun", hour_from: "22:25", hour_to: "13:45" }],
    unique = hours_array.filter((s => o => !s.has(getKey(o)) && s.add(getKey(o)))(new Set));

console.log(unique);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 2

feedy
feedy

Reputation: 1150

In this line for (let j=0; j<=hours_array.length; j++){ you can run out of the array's boundries. In your situation the array.length is 10, however when you try to access the element with index 10 you get undefined, because your last index is 9. You either have to change <= to < or reduce the length by 1. See solution below:

for (let i=0; i< hours_array.length; i++){
  for (let j=0; j<hours_array.length; j++){
    if ((hours_array[i]['hour_from'] == hours_array[j]['hour_from']) && (hours_array[i] 
    ['hour_to'] == hours_array[j]['hour_to'])){
      delete hours_array[j];
    }
  }
}

Edit: Ok you understand this issue, the next problem is that you delete an element if the array while you are still looping. There are many ways to fix this, but the easiest one is to create a new array and push the unique elements to that new array. Let me know if you need help with that.

Upvotes: 0

Related Questions