Skip to content
Advertisement

How to filter and then aggregate results in pure Javascript

Say you have two arrays and want to find the most visited group (or groups – limit will be given) in from:

const Animals = [
  { id: 1, name: "cat", group: "four legs"},
  { id: 2, name: "dog", group: "four legs"},
  { id: 3, name: "bird", group: "two legs"},
  { id: 4, name: "fish", group: "no legs"},
  { id: 5, name: "ants", group: "six legs"},
  { id: 6, name: "monkey", group: "two legs"},
  { id: 7, name: "horse", group: "four legs"},
  { id: 8, name: "spiders", group: "eight legs"},  
  { id: 9, name: "catepillar", group: "many legs"}, 
  { id: 666, name: "unused", group: "unused"}, 
]
const AnimalVisits= [
  { id: 1, visits: 40 },
  { id: 2, visits: 30 },
  { id: 3, visits: 50 }, 
  { id: 4, visits: 100 },
  { id: 5, visits: 90 }, 
  { id: 6, visits: 110 },  
  { id: 7, visits: 20 },
  { id: 8, visits: 160 }, 
  { id: 9, visits: 1000 }, 
  { id: 10, visits: 2000},//not in list!!
]
  • four legs = 90
  • two legs = 160
  • no legs = 100
  • six = 90
  • eight = 160
  • many legs = 1000
  • something not listed yet

Expected answer “many legs” for top 1.

I have written my own solution but I am not convinced it’s the most efficient as very long and would be hard to maintain plus runtime efficiency is the main concern.

I used no libraries/helpers, just pure JS. My steps were:

  • Create a new array with “group” out of Animal and AnimalVisits.
  • Aggregate by “group”.
  • Sort and filter based on the given limit.
  • Reduce to array result that outputs something like:
    • limit “1” output: “many legs”
    • limit “2” output: “many legs, eight legs”
    • limit “3” output: “many legs, eight legs, two legs”

Advertisement

Answer

You could make a dictionary with the group as the keys and loop over the visits array and keep adding to the group’s value. This handles aggregating multiple entries for the same group.

Then use Object.entries() to turn it into an array of [key, value], and sort based on the value.

Finally use Array.prototype.slice() to get the range of values you need.

const Animal= [
  { id: 1, name: "cat", group: "four legs"},
  { id: 2, name: "dog", group: "four legs"},
  { id: 3, name: "bird", group: "two legs"},
  { id: 4, name: "fish", group: "no legs"},
  { id: 5, name: "ants", group: "six legs"},
  { id: 6, name: "monkey", group: "two legs"},
  { id: 7, name: "horse", group: "four legs"},
  { id: 8, name: "spiders", group: "eight legs"},  
  { id: 9, name: "catepillar", group: "many legs"},  
]
const AnimalVisits= [
  { id: 1, visits: 40 },
  { id: 2, visits: 30 },
  { id: 3, visits: 50 }, 
  { id: 4, visits: 100 },
  { id: 5, visits: 90 },
  { id: 6, visits: 110 },
  { id: 7, visits: 20 },
  { id: 8, visits: 165 },
  { id: 9, visits: 1000 },
]

const visitDict = Animal.reduce((dict, animal) => {
  dict[animal.group] ||= 0;
  dict[animal.group] += AnimalVisits.find(obj => obj.id === animal.id).visits || 0;
  return dict
}, {})
console.log('Dictionary: ', visitDict)

const sortedArray = Object.entries(visitDict).sort((a, b) => b[1] - a[1])
console.log('Sorted: ', sortedArray)

const sortedGroups = sortedArray.map(arr => arr[0]) // Can be chained after the sort above
console.log('Sorted Groups: ', sortedGroups)

const getTop = (num) => sortedGroups
  .slice(0, num)
  .join(', ')
  
console.log('Top 3: ' + getTop(3))
User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement