0

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!

Community
  • 1
  • 1
arevilla009
  • 429
  • 3
  • 18

4 Answers4

2

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; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • I liked the concept, so kept my upvote, However, as I started thinking of it in details, there seems to be [no performance gain](https://jsperf.com/niouzxckloiuwer/1) whatsoever. – Yevhen Horbunkov Jan 23 '20 at 15:30
1

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)
Yevhen Horbunkov
  • 14,965
  • 3
  • 20
  • 42
0

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.

feedy
  • 1,071
  • 5
  • 17
  • This is only part of the problem – Bergi Jan 23 '20 at 15:07
  • The error still there with this code. Thanks for it. @Teodor Narliyski – arevilla009 Jan 23 '20 at 15:07
  • @adriano009 okay see my edit please. if you would like to do it on your own, give it a go, if not let me know and I will fix the code for you (you shouldn't delete items while you loop) - keep in mind you also need to fix what I originally wrote above – feedy Jan 23 '20 at 15:14
0

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);
Siva K V
  • 10,561
  • 2
  • 16
  • 29