分组和筛选 JSON 个文件

group and filter JSON file

我必须按艺术家对 JSON 进行分组,并得出每位艺术家的总听众总数。完成此操作后,我需要找到收听次数最多的艺术家并展示歌曲。什么是最有效的方法?我已经尝试了几种方法,但无法得到它。有没有JS函数可以做到?

这是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"
    }
]

这个JSON文件是一个例子,真正的文件有800多行。我试过列出艺术家名单,但我无法计算每位艺术家每首歌曲的听众总数。

是这样的吗?

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);

您可以将数组 reduce() 转换为 Map,这样可以直接累积重复项。您也可以只统计 运行 个听众,从而避免第二次迭代。

结果是 Map 的形状:

{
  "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));

说明

您可以继续阅读 Map and reduce() 以进一步了解。

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));