3

Currently I am trying to count multiple occurrences inside an array of objects and push a final counting into it. I do not want to have the data storred in an additional array. The data should stay in the existing one.

The array I'd try to add the count:

var array = [
    { artist: 'metallica', venue: 'olympiastadion' },
    { artist: 'foofighters', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'columbiahalle' },
    { artist: 'deftones', venue: 'columbiahalle' },
    { artist: 'deichkind', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'wuhlheide' },
    { artist: 'foofighters', venue: 'trabrennbahn' }
];

My current example code deletes/reduces from the array so the final result is not as desired:

var array = [
    { artist: 'metallica', venue: 'olympiastadion' },
    { artist: 'foofighters', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'columbiahalle' },
    { artist: 'deftones', venue: 'columbiahalle' },
    { artist: 'deichkind', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'wuhlheide' },
    { artist: 'foofighters', venue: 'trabrennbahn' }
];

array = Object.values(array.reduce((r, { artist, venue }) => {
    r[artist] = r[artist] || { artist, venue, count: 0 };
    r[artist].count++;
    return r;
}, {}));

console.log(array);

Which logs:
    { artist: 'metallica', venue: 'olympiastadion', count: 3 },
    { artist: 'foofighters', venue: 'wuhlheide', count: 2 },
    { artist: 'deftones', venue: 'columbiahalle', count: 1 },
    { artist: 'deichkind', venue: 'wuhlheide', count: 1 }

I am trying to achieve the result as:

var array = [
    { artist: 'metallica', venue: 'olympiastadion', count: 3 },
    { artist: 'foofighters', venue: 'wuhlheide', count: 2 },
    { artist: 'metallica', venue: 'columbiahalle', count: 3 },
    { artist: 'deftones', venue: 'columbiahalle', count: 1 },
    { artist: 'deichkind', venue: 'wuhlheide', count: 1 },
    { artist: 'metallica', venue: 'wuhlheide', count: 3 },
    { artist: 'foofighters', venue: 'trabrennbahn', count: 2 }
];

Any help is appreciated to point me in the right direction.

Thank you for helping! The desired solution is:

var array = [{ artist: 'metallica', venue: 'olympiastadion' }, { artist: 'foofighters', venue: 'wuhlheide' }, { artist: 'metallica', venue: 'columbiahalle' }, { artist: 'deftones', venue: 'columbiahalle' }, { artist: 'deichkind', venue: 'wuhlheide' }, { artist: 'metallica', venue: 'wuhlheide' }, { artist: 'foofighters', venue: 'trabrennbahn' }],
    map = array.reduce( 
        (map, { artist }) => map.set(artist, (map.get(artist) || 0) + 1),
        new Map
    ),
    array = array.map(o => Object.assign({}, o, { count: map.get(o.artist) }));

console.log(array);
3
  • { artist: 'metallica', venue: 'olympiastadion', count: 3 } doesn't really make sense. Commented May 12, 2019 at 18:25
  • do you want the same array object with an update, or a new array with independent new objects? Commented May 12, 2019 at 18:26
  • @Andy it might does not make sense in this tiny context here. Commented May 12, 2019 at 18:45

4 Answers 4

5

You could get the count first by iterating over all items and then assign to a new object the old object and a new count property.

var array = [{ artist: 'metallica', venue: 'olympiastadion' }, { artist: 'foofighters', venue: 'wuhlheide' }, { artist: 'metallica', venue: 'columbiahalle' }, { artist: 'deftones', venue: 'columbiahalle' }, { artist: 'deichkind', venue: 'wuhlheide' }, { artist: 'metallica', venue: 'wuhlheide' }, { artist: 'foofighters', venue: 'trabrennbahn' }],
    map = array.reduce( 
        (map, { artist }) => map.set(artist, (map.get(artist) || 0) + 1),
        new Map
    ),
    result = array.map(o => Object.assign({}, o, { count: map.get(o.artist) }));

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

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

2 Comments

Is there any advantage of using Map over an object as counter? (Because the keys are in insertion order or something like that?)
@adiga, Map#set returns the instance and needs no overhead by reducing the array.
2

You can do that in following steps:

  • Create an object from array using reduce() which have count of all the unique artists
  • The object will have keys which will different artists and their values will be their count.
  • Then use forEach on the original array.
  • Set the count of all the to the value of artist of current item in count array.

var array = [
    { artist: 'metallica', venue: 'olympiastadion' },
    { artist: 'foofighters', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'columbiahalle' },
    { artist: 'deftones', venue: 'columbiahalle' },
    { artist: 'deichkind', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'wuhlheide' },
    { artist: 'foofighters', venue: 'trabrennbahn' }
];

const unique = array.reduce((ac,{artist:a}) => (ac[a] = ac[a] + 1 || 1,ac),{});
array.forEach(x => x.count = unique[x.artist]);
console.log(array)

4 Comments

thanks for pointing it out with array.reduce this is an accepted solution as well. Question. If I want to have an additional counter "visit" of each artist occurrence how would I do it (this should add increasing visit for each artist.)?
this will add an additional property visit with the same counter result from the count variable. Is it possible to get an increasing visit for each time the artist occurred?
@huppen This const unique = array.reduce((ac,{artist:a},i) => (array[i].visit = ac[a] = ac[a] + 1 || 1,ac),{}); may solve your problem.
Thank you for your help. The last codes solves my question in the comment :-)
0

You can do one pass over the array building a map of artist name to a count, and a second pass to modify each array item adding the count associated with the artist.

var array = [
    { artist: 'metallica', venue: 'olympiastadion' },
    { artist: 'foofighters', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'columbiahalle' },
    { artist: 'deftones', venue: 'columbiahalle' },
    { artist: 'deichkind', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'wuhlheide' },
    { artist: 'foofighters', venue: 'trabrennbahn' }
];

var counts = array.reduce((counts, item) => {
  var artistName = item.artist;
  if (counts[artistName]) {
    counts[artistName] += 1;
  } else {
    counts[artistName] = 1;
  }
  
  return counts;
}, {});

array.forEach(item => item.count = counts[item.artist])

console.log(array);

The .reduce function is verbose for clarity but it can be shortened a lot:

var array = [
    { artist: 'metallica', venue: 'olympiastadion' },
    { artist: 'foofighters', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'columbiahalle' },
    { artist: 'deftones', venue: 'columbiahalle' },
    { artist: 'deichkind', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'wuhlheide' },
    { artist: 'foofighters', venue: 'trabrennbahn' }
];

var counts = array.reduce((counts, item) => (counts[item.artist] = counts[item.artist] || 1, counts), {});

console.log(counts);

If you want to create a new array instead of modifying the objects in the old one, then you can make a copy of each object and the array:

var array = [
    { artist: 'metallica', venue: 'olympiastadion' },
    { artist: 'foofighters', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'columbiahalle' },
    { artist: 'deftones', venue: 'columbiahalle' },
    { artist: 'deichkind', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'wuhlheide' },
    { artist: 'foofighters', venue: 'trabrennbahn' }
];

var counts = {
  "metallica": 3,
  "foofighters": 2,
  "deftones": 1,
  "deichkind": 1
}

var newArray = array.map(item => ({...item, count: counts[item.artist]}))

console.log(newArray);
console.log(array);

Comments

0

You can iterate two times over the array.

var array = [
    { artist: 'metallica', venue: 'olympiastadion' },
    { artist: 'foofighters', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'columbiahalle' },
    { artist: 'deftones', venue: 'columbiahalle' },
    { artist: 'deichkind', venue: 'wuhlheide' },
    { artist: 'metallica', venue: 'wuhlheide' },
    { artist: 'foofighters', venue: 'trabrennbahn' }
];

array.forEach(a => {
  if (!a.hasOwnProperty('count')) {
    Object.assign(a, { count: 0 });
  }
  array.forEach(b => {
    if (a.artist === b.artist) {
      a.count++;
    }
  });
});

console.log(array);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.