分组和筛选 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));
我必须按艺术家对 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));