0

I have a JSON file with over 20k entries with the names of different tracks on Spotify. I was trying to count the number of times each song has been played by a specific artist.

function countInArray(array, what) {
    var count = 0;
    for (var i = 0; i < array.length; i++) {
        if (array[i] === what) {
            count++;
        }
    }
    nfPlays.push(count)
    return count;
}
nfSongs2 = []
nfSongs = []
nfPlays = []

for(var i = 0; i < dta.length; i++) {
  if(dta[i].artistName === "NF") {
    nfSongs.push(dta[i].trackName)
  }
}
for(var i = 0; i < dta.length; i++) {
  if(nfSongs2.indexOf(dta[i].trackName) === -1 && dta[i].artistName === "NF") {
    nfSongs2.push(dta[i].trackName)
  }
}

for(var i = 0; i < nfSongs2.length; i++) {
  console.log(`${nfSongs2[i]} has ${countInArray(nfSongs, nfSongs2[i])} plays`)

}

console.log(countInArray(nfSongs, "WHY"))

console.log(nfPlays)
console.log(nfSongs2)
console.log(nfSongs)

That's currently my code. Basically what it does is loop through the dta array and grab all the entries by NF (specifically the track names) which includes the duplicates, and then it does that again but this time, only grabbing unique names. Then I run countInArray on all the unique names of the tracks which will grab the number of plays and push it to the nfPlays array.

Not especially complicated and it does work. I was wondering if there is a better, shorter way of doing this.

vic-st
  • 5
  • 1
  • 6

3 Answers3

0

I think you should try the filter method. For example:

function countInArray(array, what) {
    const foundItems = array.filter(value => value === what);
    nfPlays.push(foundItems.length)
    return foundItems.length;
}

Or

const foundTracks = dta.filter(track => track.artistName === "NF");

Background

Michael Rodriguez
  • 1,996
  • 1
  • 7
  • 15
0

You can use a Map which is presents a faster lookup than an array (indexOf)

const dta = [
  { trackName:'a', artistName:'NF' },
  { trackName:'a', artistName:'NF' },
  { trackName:'b', artistName:'NF' },
  { trackName:'b', artistName:'other' },
]
const trackNameToCount = dta.reduce((m, track) => {
  if (track.artistName === 'NF') {
    const n = m.get(track.trackName) || 0
    m.set(track.trackName, n+1)
  }
  return m
}, new Map())

;[...trackNameToCount.entries()].forEach(([name, count]) => {
  console.log(`${name} played ${count} times`)
})
grodzi
  • 5,260
  • 1
  • 13
  • 13
  • Could the values be pushed to an array? – vic-st Dec 14 '19 at 23:23
  • I don't know to which values you refer to, but yes they can be pushed to an array – grodzi Dec 14 '19 at 23:24
  • @Steve [no](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map). not supported for IE. use a polyfill or the built in Object ({}) if need be – grodzi Dec 15 '19 at 20:29
  • @grodzi What advantage do you see using maps over built in objects? – Steve Dec 16 '19 at 16:48
  • @steve tldr Here it is mainly just semantics. There's a lot of more objective [content](https://stackoverflow.com/questions/18541940/map-vs-object-in-javascript). To me though I just like Map.prototype.has. I like less and less typing Object(stuff)...which is lengthy (be it keys, values, entries, hasOwnProperty, ..). On the same hand the main drawback of Map is that it is verbose for incrementing stuff. Hopefully [upsert](https://github.com/tc39/proposal-upsert) or something else may come, and at least we are aware that it is a bit cumbersome. Perf is nice to have but not relevant here. – grodzi Dec 16 '19 at 17:30
0

Hope I understand what you're doing. I'd suggest using the object type to handle duplicates. Something like this?

dta = [
  {trackName: "dog", artistName: "NF"},
  {trackName: "dog", artistName: "mack"},
  {trackName: "dog", artistName: "NF"},
  {trackName: "cat", artistName: "fred"},
  {trackName: "mouse", artistName: "NF"},
]

nfsongs = {}

dta.forEach(item => {
    if (item.artistName==="NF") {
        if (item.trackName in nfsongs) {
            nfsongs[item.trackName]++;
        } else {
            nfsongs[item.trackName]=1;
        }
    }
})

for (key in nfsongs) {
    console.log(`${key} has ${nfsongs[key]} plays`)
}
Steve
  • 675
  • 2
  • 18