5

How can I compare multiple arrays of objects and add new properties with the number of occurrences an object was found and the array indexes where the object was found? The object comparison must be made by the name property.

Example:

var arrays = [
  [
    {
      name: 'aa',
      value: 1
    },
    {
      name: 'ab',
      value: 2
    },
    {
      name: 'ac',
      value: 3
    },
    {
      name: 'aa',
      value: 1
    }
  ],
  [
    {
      name: 'aa',
      value: 1
    },
    {
      name: 'ab',
      value: 2
    },
  ],
  [
    {
      name: 'ac',
      value: 3
    },
    {
      name: 'aa',
      value: 1
    }
  ]
]

After execution the object from the above array should have these properties:

[
  [
    {
      name: 'aa',
      value: 1,
      occurrences: 3,
      where: [0, 1, 2]
    },
    {
      name: 'ab',
      value: 2,
      occurrences: 2,
      where: [0, 1]
    },
    {
      name: 'ac',
      value: 3,
      occurrences: 2,
      where: [0, 2]
    },
    {
      name: 'aa',
      value: 1,
      occurrences: 3,
      where: [0, 1, 2]
    }
  ],
  [
    {
      name: 'aa',
      value: 1,
      occurrences: 3,
      where: [0, 1, 2]
    },
    {
      name: 'ab',
      value: 2,
      occurrences: 2,
      where: [0, 1]
    }
  ],
  [
    {
      name: 'ac',
      value: 3,
      occurrences: 2,
      where: [0, 2]
    },
    {
      name: 'aa',
      value: 1,
      occurrences: 3,
      where: [0, 1, 2]
    }
  ]
]

Basically I want to check if the object with a specific name property exists in the other arrays.

This is the solution that comes in my mind: 1. Loop through the array that has the most objects
2. Loop through each object
3. Loop through the other arrays and apply Array.prototype.find()
But this will take a lot of time since each of my array will have at least 500 objects...

2
  • 1
    Straightforward solution with loop in loop will work. Might not be the most efficient but if you don't have too many objects then it's fine. Commented Nov 20, 2017 at 10:44
  • I wanted to implement a loop in loop but each array will have at least 500 objects Commented Nov 20, 2017 at 10:45

2 Answers 2

1

You can use array#reduce to get the number of occurrences and the index of occurrences in an object.

Then, you can modify your object in the arrays by simply using Object.assign() and adding the where and occurrences property.

var arrays = [ [ { name: 'aa', value: 1 }, { name: 'ab', value: 2 }, { name: 'ac', value: 3 }, { name: 'aa', value: 1 } ], [ { name: 'aa', value: 1 }, { name: 'ab', value: 2 }, ], [ { name: 'ac', value: 3 }, { name: 'aa', value: 1 } ] ];

var result = arrays.reduce((res, arr, index) => {
  arr.forEach(({name,value}) => {
    res[name] =  res[name] || {occurrences: 0};
    res[name]['where'] = res[name]['where'] || [];
    if(!res[name]['where'].includes(index)){
      res[name]['where'].push(index);
      res[name].occurrences += 1;
    }
  });
  return res;
},{});

arrays.forEach(arr => arr.forEach(obj => Object.assign(obj, result[obj.name])));
console.log(arrays);

Sign up to request clarification or add additional context in comments.

2 Comments

This works great, but how can I modify the code to not count the duplicates from an array? I only want to see if an object exists in an array and just count it once, even if the array where it was found contains multiple objects with that name
I have updated the code to not count the duplicates from the array. if(!res[name]['where'].includes(index)){ line checks for duplicate.
1

This looked like trivial reduce, until i noticed nested arrays ) so it's more like flatten + reduce, with memory.

Code below is doing what you need, just the prop names are short (as i type them on the phone):

let f = (ai, a,v,i,m) => {
    if (!a[v.id]) {
    a[v.id] = {id: v.id, v: v.name, count: 1, at: [ai]};
    } else {
    a[v.id].count += 1;
    a[v.id].at.push(ai);
    }
    return a;
};
let r = [[{id: 'aa', value: 42}], [{id: 'ba', value: 11}, {id: 'aa', value: 42}]]
.reduce ((a, v, i) => v.reduce (f.bind (null, i),a), {}); 
console.log (r);

Code still visits each element in any array only once, so complexity is O(n), and there should not be a problem running it on arrays up to a million of total elements (e.g. 1000 arrays of 1000 elements, or 200 x 5000).

3 Comments

How can I modify the code to not count the duplicates from an array? I only want to see if an object exists in an array and just count it once, even if the array where it was found contains multiple objects with that name.
Which of the counters ? Occurance counter or host array counter ?
Host array counter ... meaning that if an array has 3 occurrences of an object it should be counted just once. I just need to see if the object exists in that array.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.