2

I have an array of objects where each object has a an id key. some of those objects have re-occuring id's and I want to remove those re-occuring objects.

So for instance:

let array = [{
    "id": "123",
    "country": "Brazil",
    "address": "xyz abc",
    "date": "Dec 17, 1995, 9:45:17 PM"
  },
  {
    "id": "443",
    "country": "Russia",
    "address": "qwd qwd qwdqw",
    "date": "Dec 17, 1965, 9:45:17 PM"
  },
  {
    "id": "123",
    "country": "Canada",
    "address": "ktktkt",
    "date": "Dec 17, 1925, 9:45:17 PM"
  },
.
.
.
{}]

in the array above since index 0 and index 2 share the same id key value, I would like to completely remove them both from the array.

  • I am looking for optimal code in terms of complexity, only linear (O(n)).
Bardr
  • 2,319
  • 2
  • 12
  • 21
clusterBuddy
  • 1,523
  • 12
  • 39
  • 2
    This isn't a use case for `reduce`. It might be a use case for `filter`, but really, a simple loop keeping track of objects you've seen for a given ID before temporarily in a `Map` (or an object) is all you need. Your best bet here is to do your research, [search](/help/searching) for related topics on SO, and give it a go. ***If*** you get stuck and can't get unstuck after doing more research and searching, post a [mcve] of your attempt and say specifically where you're stuck. People will be glad to help. – T.J. Crowder Feb 27 '19 at 08:35
  • There are dozens of questions with answers on SO about how to do that. – T.J. Crowder Feb 27 '19 at 08:37
  • 2
    Possible duplicate of [Remove duplicate values from an array of objects in javascript](https://stackoverflow.com/questions/45439961/remove-duplicate-values-from-an-array-of-objects-in-javascript) and [Remove duplicates from an array of objects in JavaScript](https://stackoverflow.com/questions/2218999) and [Remove Duplicates from an Array of GeoFire Objects](https://stackoverflow.com/questions/52480479) and [Removing duplicates in array of objects](https://stackoverflow.com/questions/13743859) – adiga Feb 27 '19 at 08:37
  • 1
    Am I missing something or you made a typo? Linear complexity is represented by `O(n)` not `log(O)` (I don't even know how to read this nor what it is). – Bardr Feb 27 '19 at 09:07
  • Bardr - you are correct and some gentleman (or woman! lol) gallantly edited it for me, thanks! – clusterBuddy Feb 27 '19 at 09:16

8 Answers8

1

I don't know, maybe this?:

array.filter(function(d,i){return !this[d.id] && (this[d.id] = d.id)},{})
ibrahim tanyalcin
  • 5,643
  • 3
  • 16
  • 22
1

Since you want to remove completely the repeated values you can try this. First find the repetitions and then filter the original array.

let array = [{
    "id": "123",
    "country": "Brazil"
  },{
    "id": "443",
    "country": "Russia"
  },{
    "id": "123",
    "country": "Canada"
  },{
    "id": "123",
    "country": "Canada"
  },{
    "id": "345",
    "country": "UK"
  }];

const removeDups = (data) => {
 
 const dups = data.reduce((acc, { id }) => {
  acc[id] = (acc[id] || 0) + 1;
  return acc;
 }, {});

 return data.filter(({ id }) => dups[id] === 1);
}

console.log(removeDups(array));
Alex G
  • 1,897
  • 2
  • 10
  • 15
  • I really like this function that segregates the duplicate counting and then goes in to filter. What's the complexity of `removeDups()` ? – clusterBuddy Feb 27 '19 at 09:14
  • 1
    @clusterBuddy Thank you, I believe it's O(n). – Alex G Feb 27 '19 at 09:19
  • Thanks Alex. i'm learning how to use reduce, can I use in this function a counter to count the reoccurance of country names in reducer? – clusterBuddy Feb 27 '19 at 09:21
  • 1
    @clusterBuddy Yes you could use the country prop instead of the id. So you would end up with an object, countries as keys and the reoccurances as values. – Alex G Feb 27 '19 at 09:24
1

No need for reduce, just sort and filter:

let array = [{
    "id": "123",
    "country": "Brazil",
    "address": "xyz abc",
    "date": "Dec 17, 1995, 9:45:17 PM"
  },
  {
    "id": "443",
    "country": "Russia",
    "address": "qwd qwd qwdqw",
    "date": "Dec 17, 1965, 9:45:17 PM"
  },
  {
    "id": "123",
    "country": "Canada",
    "address": "ktktkt",
    "date": "Dec 17, 1925, 9:45:17 PM"
  },
  
]


const output = array.sort((a, b) => a.id - b.id).filter((item, index, sorted) => {
  const before = sorted[index - 1] || {}
  const after = sorted[index + 1] || {}

  return item.id !== after.id && item.id !== before.id
})

console.log(output);
thedude
  • 9,388
  • 1
  • 29
  • 30
0

You don't need reduce at all - a simple for loop does the job:

let array = [{
    "id": "123",
    "country": "Brazil",
    "address": "xyz abc",
    "date": "Dec 17, 1995, 9:45:17 PM"
  },
  {
    "id": "443",
    "country": "Russia",
    "address": "qwd qwd qwdqw",
    "date": "Dec 17, 1965, 9:45:17 PM"
  },
  {
    "id": "123",
    "country": "Canada",
    "address": "ktktkt",
    "date": "Dec 17, 1925, 9:45:17 PM"
  }
]

array.forEach(i => {
  let found = false
  array.forEach(j => {
    if (j == i) {
      found++;
    }
  });
  if (found) {
    array.forEach((k, l) => {
      if (k == i) {
        array.splice(l, 1);
        l--;
      }
    });
  }
});

console.log(array);
Jack Bashford
  • 43,180
  • 11
  • 50
  • 79
0

One solution would be to aggregate the input array to a key/value map, where the value is a list of items sharing the same id. You'd then extract an array from this map via Object.values(), filter values with more than one item, and then map those single items to the final output:

let array = [{
    "id": "123",
    "country": "Brazil",
    "address": "xyz abc",
    "date": "Dec 17, 1995, 9:45:17 PM"
  },
  {
    "id": "443",
    "country": "Russia",
    "address": "qwd qwd qwdqw",
    "date": "Dec 17, 1965, 9:45:17 PM"
  },
  {
    "id": "123",
    "country": "Canada",
    "address": "ktktkt",
    "date": "Dec 17, 1925, 9:45:17 PM"
  }
]

const result = Object.values(array.reduce((map, item) => {

    map[item.id] = (map[item.id] || []).concat([item]);

    return map;

  }, {}))
  .filter(item => item.length === 1)
  .map(([item]) => item)

console.log(result)
Dacre Denny
  • 29,664
  • 5
  • 45
  • 65
0

You can simply initialize an count object and populate it using a simple forEach loop then just use filter.

let arr = [{ id: "123", country: "Brazil", address: "xyz abc", date: "Dec 17, 1995, 9:45:17 PM" }, { id: "443", country: "Russia", address: "qwd qwd qwdqw", date: "Dec 17, 1965, 9:45:17 PM" }, { id: "123", country: "Canada", address: "ktktkt", date: "Dec 17, 1925, 9:45:17 PM" }]

count = {}

arr.forEach(obj => {
  if (count[obj.id]) {
      count[obj.id] += 1
  } else {
      count[obj.id] = 1
  } 
})



console.log(arr.filter(obj => count[obj.id] === 1))

Run time (code-complexity): O(N)

BlackBeard
  • 10,246
  • 7
  • 52
  • 62
0

Use Array.reduce() to build an intermediate dictionary by id whose values are all items with that id. Then enumerate the values of this dictionary with Object.values() and filter out the entries with multiple elements using Array.filter(), then flatten the result using Array.flat():

const array = [{
    "id": "123",
    "country": "Brazil",
    "address": "xyz abc",
    "date": "Dec 17, 1995, 9:45:17 PM"
  },
  {
    "id": "443",
    "country": "Russia",
    "address": "qwd qwd qwdqw",
    "date": "Dec 17, 1965, 9:45:17 PM"
  },
  {
    "id": "123",
    "country": "Canada",
    "address": "ktktkt",
    "date": "Dec 17, 1925, 9:45:17 PM"
  },
];

const singles = Object.values(array.reduce((acc, x) => {
  acc[x.id] = [...(acc[x.id] || []), x];
  return acc;
}, {})).filter(x => x.length === 1).flat();

console.log(singles);
jo_va
  • 13,504
  • 3
  • 23
  • 47
0

You could take a Map and if exist, set the mapeed array to the length of zero. At the end concat all arrays.

var array = [{ id: "123", country: "Brazil", address: "xyz abc", date: "Dec 17, 1995, 9:45:17 PM" }, { id: "443", country: "Russia", address: "qwd qwd qwdqw", date: "Dec 17, 1965, 9:45:17 PM" }, { id: "123", country: "Canada", address: "ktktkt", date: "Dec 17, 1925, 9:45:17 PM" }],
    result = [].concat(...array.map((m => (o, i) => {
        var temp = [];
        if (m.has(o.id)) {
            m.get(o.id).length = 0;
        } else {
            m.set(o.id, temp = [o]);
        }
        return temp;
   })(new Map)))

console.log(result);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392