-4

I need help to make a function to search using vanilla or for example lodash to loop an a array of objects and get the highest occurrence object in the array, this is my object:

[{"s":97,"p":75},{"s":99,"p":93},{"s":97,"p":75},{"s":97,"p":76},{"s":97,"p":75},{"s":97,"p":75},{"s":97,"p":74},{"s":86,"p":80},{"s":97,"p":73},{"s":97,"p":71},{"s":97,"p":71}]

the result should be:

{"s":97,"p":75}

thanks in advance

Yevhen Horbunkov
  • 14,965
  • 3
  • 20
  • 42
Alexis
  • 1
  • 3
  • 3
    have you tried anything? what goes wrong? – Nina Scholz Jul 23 '20 at 15:16
  • Here you go https://stackoverflow.com/questions/1053843/get-the-element-with-the-highest-occurrence-in-an-array You can use any of those methods, or simply do JSON.stringify(eachObject) and than compare them, filter them, reduce them, or any other method you like. – Victor Jul 23 '20 at 15:28

3 Answers3

2

You may traverse your source array with Array.prototype.reduce() building up a complex object to keep track of each object occurrence, the object most often seen so far and the number of times that most often object was actually seen.

So, once some of array items exceeds maxCount it becomes mostOften.

With that you may do only single pass through all items to find the winner:

const src = [{"s":97,"p":75},{"s":99,"p":93},{"s":97,"p":75},{"s":97,"p":76},{"s":97,"p":75},{"s":97,"p":75},{"s":97,"p":74},{"s":86,"p":80},{"s":97,"p":73},{"s":97,"p":71},{"s":97,"p":71}],

      {mostOften} = src.reduce((r,{s,p}) => {
        const hash = s+'\ud8ff'+p
        r.hashCount[hash] = (r.hashCount[hash]||0) + 1
        r.hashCount[hash] > r.maxCount &&
        (r.mostOften = {s,p}, r.maxCount = r.hashCount[hash])
        return r
      }, {hashCount: {}, mostOften: null, maxCount: 0})
      
console.log(mostOften)      
      
Yevhen Horbunkov
  • 14,965
  • 3
  • 20
  • 42
0

The important thing here is to have a reliable key for what you consider the "same" objects. I would suggest JSON.stringify on the array formed by the two properties:

let data = [{"s":97,"p":75},{"s":99,"p":93},{"s":97,"p":75},{"s":97,"p":76},{"s":97,"p":75},{"s":97,"p":75},{"s":97,"p":74},{"s":86,"p":80},{"s":97,"p":73},{"s":97,"p":71},{"s":97,"p":71}];

let keys = Object.fromEntries(data.map(o => [ JSON.stringify([o.s, o.p, "s" in o, "p" in o]), o ]));
let counter = {};
for (let key in keys) counter[key] = (counter[key] || 0) + 1;
let bestKey = Object.entries(counter).reduce((max, [key, count]) =>
    count > max[1] ? [key, count] : max, ["", 0])[0];
    
let result = keys[bestKey];
console.log(result);

Even when s or p are strings with any foreign character, or booleans, or null, or arrays of (arrays of) primitives, ...this will still work.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • Why `JSON.stringify()` for an array of two numbers? `o => \`${o.s},${o.p}\`` – Andreas Jul 23 '20 at 15:37
  • `Object.values(o).join('\ud8ff')` would be whole lot better choice, than `JSON.stringify()` – Yevhen Horbunkov Jul 23 '20 at 15:38
  • Who says they will always be numbers, @Andreas? – trincot Jul 23 '20 at 15:40
  • Really, @YevgenGorbunkov? What if that character is used in string values in the data? These are exactly the things you avoid with JSON. – trincot Jul 23 '20 at 15:41
  • What if the array will also contain other arrays? Or functions? Or ...? OP asks for a solution for the given array which only has numbers in it. If you want to write something totally bulletproof then... – Andreas Jul 23 '20 at 15:42
  • JSON can deal with other arrays just fine. It would be far-fetched to consider functions in data. I think it is much more reasonable though to count strings within the scope. – trincot Jul 23 '20 at 15:45
  • @trincot : I would say the odds of having `\ud8ff` (invalid character) among your input are much less, than encountering for example `{s: 1}` and `{s:1, p: null}` which are *technically* different objects while both get `JSON.stringify()`'ed into `[1, null]` following your method. And I don't even mention some more tricky cases... – Yevhen Horbunkov Jul 23 '20 at 16:07
  • For the example you gave, I have adapted my code, as indeed the absence of a property seems a likely use case. – trincot Jul 23 '20 at 16:29
-3

let arr = [{"s":97,"p":75},{"s":99,"p":93},{"s":97,"p":75},{"s":97,"p":76},{"s":97,"p":75},{"s":97,"p":75},{"s":97,"p":74},{"s":86,"p":80},{"s":97,"p":73},{"s":97,"p":71},{"s":97,"p":71}]
let obj = {};
let maxCount = 0;
let result;
arr.forEach(e => {
  let key = `s:${e.s}:p:${e.p}`;
  obj[key] = obj[key] || 0;
  obj[key] += 1;
  if(obj[key] > maxCount){
    maxCount = obj[key];
    result = e;
  }
});
console.log(result);
vcode
  • 453
  • 4
  • 8
  • Done. Thanks @Andreas for the correction. – vcode Jul 23 '20 at 15:33
  • 1
    This will consider the following objects the same: `{ s: 111, p: 1 }` and `{ s:1, p:111 }`. This answer should not have been accepted. – trincot Jul 23 '20 at 15:35
  • @trincot Thanks for pointing out. Corrected. – vcode Jul 23 '20 at 15:36
  • So what if the values of either `s` or `p` are strings having also "s" or "p" letters? For instance `{ s: "ap", p: "p" }` will now be considered equal to `{ s: "a", p: "pp" }` – trincot Jul 23 '20 at 15:37
  • @trincot Its an excellent query. I accept this can't be a valid solution for all cases. I have made an edit to the code. Please let me know if you think it has a problem. Your comments made me more interested. Thanks. – vcode Jul 23 '20 at 15:45
  • 1
    Adding more characters is not a robust solution. Now think of `{ s: "a:p:b", p: "a" }` and `{ s: "a", p: "b:p:a" }`. Adding more characters will make it more improbable that such things happen, but there will always be a loophole. – trincot Jul 23 '20 at 15:52
  • @trincot Accepting your comment. – vcode Jul 23 '20 at 15:53