简体   繁体   中英

group and filter JSON file

I have to group this JSON by artist and get the sumatory of total listeners per artist. Once this is done I need to get the most listened artist and show h the songs. What would be the most efficient way? I've tryed several ways but can't get it. Is there any JS function to do it?

This is the JSON:

[
    {
        "name": "The Less I Know the Better",
        "duration": "0",
        "listeners": "439958",
        "mbid": "",
        "url": "https://www.last.fm/music/Tame+Impala/_/The+Less+I+Know+the+Better",
        "artist": {
            "name": "Tame Impala",
            "mbid": "63aa26c3-d59b-4da4-84ac-716b54f1ef4d",
            "url": "https://www.last.fm/music/Tame+Impala"
        },
        "@attr": {
            "rank": "0"
        },
        "genre": "reggae"
    },
    {
        "name": "Creep",
        "duration": "239",
        "listeners": "1647583",
        "mbid": "d11fcceb-dfc5-4d19-b45d-f4e8f6d3eaa6",
        "url": "https://www.last.fm/music/Radiohead/_/Creep",
        "artist": {
            "name": "Radiohead",
            "mbid": "a74b1b7f-71a5-4011-9441-d0b5e4122711",
            "url": "https://www.last.fm/music/Radiohead"
        },
        "@attr": {
            "rank": "1"
        },
        "genre": "jazz"
    }
]

This JSON file it's an example, the real one is more than 800 lines long. I've tried doing a list of artists but then I can not sum the total listeners for each song of each artists.

Something like this?

 const json = ` [{ "name": "The Less I Know the Better", "duration": "0", "listeners": "439958", "mbid": "", "url": "https://www.last.fm/music/Tame+Impala/_/The+Less+I+Know+the+Better", "artist": { "name": "Tame Impala", "mbid": "63aa26c3-d59b-4da4-84ac-716b54f1ef4d", "url": "https://www.last.fm/music/Tame+Impala" }, "@attr": { "rank": "0" }, "genre": "reggae" }, { "name": "Creep", "duration": "239", "listeners": "1647583", "mbid": "d11fcceb-dfc5-4d19-b45d-f4e8f6d3eaa6", "url": "https://www.last.fm/music/Radiohead/_/Creep", "artist": { "name": "Radiohead", "mbid": "a74b1b7f-71a5-4011-9441-d0b5e4122711", "url": "https://www.last.fm/music/Radiohead" }, "@attr": { "rank": "1" }, "genre": "jazz" }, { "name": "Other song of Radiohead for example", "duration": "239", "listeners": "1647583", "mbid": "d11fcceb-dfc5-4d19-b45d-f4e8f6d3eaa6", "url": "https://www.last.fm/music/Radiohead/_/Creep", "artist": { "name": "Radiohead", "mbid": "a74b1b7f-71a5-4011-9441-d0b5e4122711", "url": "https://www.last.fm/music/Radiohead" }, "@attr": { "rank": "1" }, "genre": "jazz" } ]` const artists = {}; for (const song of JSON.parse(json)) { if (artists[song.artist.name]) { artists[song.artist.name].listeners += parseInt(song.listeners, 10); artists[song.artist.name].songs.push(song.name); } else { artists[song.artist.name] = { listeners: parseInt(song.listeners, 10), songs: [song.name], }; } } console.log(artists);

You can reduce() the array into a Map which makes accumulating duplicates straightforward. You can also just have a running tally of listeners thus avoiding a second iteration.

The result is a Map of the shape:

{
  "Artist1": {
    "songs": [
      {...},
      {...}
    ]
    "listeners": 0
  },
  "Artist2": {
    "songs": [
      {...},
      {...}
    ]
    "listeners": 0
  }
  ...
}

 const songs = [ { "name": "The Less I Know the Better", "duration": "0", "listeners": "439958", "mbid": "", "url": "https://www.last.fm/music/Tame+Impala/_/The+Less+I+Know+the+Better", "artist": { "name": "Tame Impala", "mbid": "63aa26c3-d59b-4da4-84ac-716b54f1ef4d", "url": "https://www.last.fm/music/Tame+Impala" }, "@attr": { "rank": "0" }, "genre": "reggae" }, { "name": "Creep", "duration": "239", "listeners": "1647583", "mbid": "d11fcceb-dfc5-4d19-b45d-f4e8f6d3eaa6", "url": "https://www.last.fm/music/Radiohead/_/Creep", "artist": { "name": "Radiohead", "mbid": "a74b1b7f-71a5-4011-9441-d0b5e4122711", "url": "https://www.last.fm/music/Radiohead" }, "@attr": { "rank": "1" }, "genre": "jazz" }, { "name": "Go to Sleep", "duration": "239", "listeners": "16583", "mbid": "d11fcceb-dfc5-4d19-b45d-f4e8f6d3eaa6", "url": "https://www.last.fm/music/Radiohead/_/Go to Sleep", "artist": { "name": "Radiohead", "mbid": "a74b1b7f-71a5-4011-9441-d0b5e4122711", "url": "https://www.last.fm/music/Radiohead" }, "@attr": { "rank": "3" }, "genre": "jazz" } ] const byArtist = songs.reduce((acc, song) => { const artistName = song.artist.name; const match = acc.get(artistName); if (match) { match.songs.push({...song}); match.listeners += parseInt(song.listeners); } else { acc.set(artistName, {songs: [{...song}], listeners: +song.listeners}); } return acc; }, new Map); console.log(Object.fromEntries(byArtist));

Explanation

You can read up on Map and reduce() for further insight.

const byArtist = songs.reduce((acc, song) => {
  // get the artist name from the current song object
  const artistName = song.artist.name;
  // try to get the element referenced by artistName,
  // returns undefined if we haven't added that artist yet
  // otherwise it returns the object holding "songs" and "listeners"
  const match = acc.get(artistName);
  if (match) {
    // if match is truthy (successfully retrieved an entry)
    // push a copy of the song into the "songs" array
    match.songs.push({...song});
    // increment the listener count by the songs listeners
    match.listeners += parseInt(song.listeners);
  } else {
    // else set a new key: value pair useing artistName as the key
    // and creating a new object contianing "songs" and "listeners"
    acc.set(artistName, {songs: [{...song}], listeners: +song.listeners});
  }
  // return the mutated accumulator for the next iteration to use.
  return acc;
}, new Map); // this initializes the accumulator as a new Map object

// creates an Object from the Map so that it can be logged easily
console.log(Object.fromEntries(byArtist));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM