はじめに
JavascriptでJSONを扱う機会が多いのでまとめてみます。mapとかreduceとかそろそろ使いこなせるようになりたいです。
前提
扱うJSONは下のような感じにしました。気分です。最近iPod卒業して以下の3つを品定め中だからです。ランキングは一部抜粋、今Apple Musicに傾きつつあるので、他のやつのランキングはスキップで。まあだいたい同じですし。
var sample = {
Music_Services:[
{
Service: "Apple Music",
Company: "Apple",
Top_Song_Ranking:{
observation_date: "2019-02-09",
ranking:[
{
artist: "あいみょん",
song: "マリーゴールド",
rank: 1
},
{
artist: "ONE OK ROCK",
song: "Stand Out Fit In",
rank: 2
},
{
artist: "あいみょん",
song: "今夜このまま",
rank: 3
},
{
artist: "エド・シーラン",
song: "Shape of You",
rank: 7
},
{
artist: "あいみょん",
song: "愛を伝えたいだとか",
rank: 9
}
]
}
},
{
Service: "Google Play Music",
Company: "Google",
Top_Song_Ranking: null
},
{
Service: "Spotify",
Company: "Spotify AB",
Top_Song_Ranking: null
}
]
}
* データ構造は適当に作ったものでApple MusicのAPI定義とかに合わせたりしてません。
参照
レコード参照
「音楽サービスのどんなデータ入ってるのかザーッと見たい」
sample["Music_Services"].forEach((item) => {
console.log(item)
})
↓
{ Service: 'Apple Music',
Company: 'Apple',
Top_Song_Ranking:
{ observation_date: '2019-02-09',
ranking: [ [Object], [Object], [Object], [Object], [Object] ] } }
{ Service: 'Google Play Music',
Company: 'Google',
Top_Song_Ranking: null }
{ Service: 'Spotify',
Company: 'Spotify AB',
Top_Song_Ranking: null }
[Object]の中身表示したかったらconsole.log(JSON.stringify(item))
にすれば見れますね。
プロパティ参照
「一覧だと見づらいからどんな属性があるかだけ見たい」
var firstService = sample["Music_Services"][0]
Object.keys(firstService).forEach((data) => {
console.log(data);
})
↓
Service
Company
Top_Song_Ranking
「もっと深い属性が見たい」
Object.keys(firstService["Top_Song_Ranking"]).forEach((data) => {
console.log(data);
})
console.log("====")
var firstSong = firstService["Top_Song_Ranking"]["ranking"][0]
Object.keys(firstSong).forEach((data) => {
console.log(data);
})
↓
observation_date
ranking
====
artist
song
rank
基本的に1つ目のレコードだけサンプル的にとってきて中を覗く感じです。レコードによってプロパティに過不足ある場合とかは対象外で。
検索
単一検索
「Apple Musicの情報だけ欲しい」
const AppleMusic = sample["Music_Services"].find((item, index) => {
return (item.Service === "Apple Music")
})
/*こっちでもおなじ
const AppleMusic = sample["Music_Services"].find((item, index) => {
if(item.Service === "Apple Music") return true
})
*/
console.log(AppleMusic)
↓
{ Service: 'Apple Music',
Company: 'Apple',
Top_Song_Ranking:
{ observation_date: '2019-02-09',
ranking: [ [Object], [Object], [Object], [Object], [Object] ] } }
ここからはApple Musicしか眼中に入れません。
なので、変数 "AppleMusic"を使いまわします。
複数検索
「あいみょんの曲ってどんぐらいランキング入ってるんだろ」
const Aimyon_Songs = AppleMusic["Top_Song_Ranking"]["ranking"].filter((item, index) => {
return (item.artist === "あいみょん")
})
console.log(Aimyon_Songs)
↓
[ { artist: 'あいみょん', song: 'マリーゴールド', rank: 1 },
{ artist: 'あいみょん', song: '今夜このまま', rank: 3 },
{ artist: 'あいみょん', song: '愛を伝えたいだとか', rank: 9 } ]
*本当は他にももっと入ってますよ
「英語タイトルの曲どんくらいランキング入ってるんだろ」
const English_Titles = AppleMusic["Top_Song_Ranking"]["ranking"].filter((item, index) => {
return (item.song.match(/[a-zA-Z]/))
})
console.log(English_Titles)
↓
[ { artist: 'ONE OK ROCK', song: 'Stand Out Fit In', rank: 2 },
{ artist: 'エド・シーラン', song: 'Shape of You', rank: 7 } ]
*おまけ
filterは複数検索の時ですね。findも兼ねますが、なんとなく使い分けたいなと。
制限
「曲名だけ一覧でバーっと見たい」
const song_names = AppleMusic["Top_Song_Ranking"]["ranking"].map(x => x["song"])
console.log(song_names)
↓
[ 'マリーゴールド',
'Stand Out Fit In',
'今夜このまま',
'Shape of You',
'愛を伝えたいだとか' ]
mapって主にこういうときに使うイメージですね。他にもあるかな。
集約
「結局ランキングにどういうアーティストが何曲ずつくらい入ってるんだろ」
const summary = AppleMusic["Top_Song_Ranking"]["ranking"].reduce((accum, current)=> {
//同じアーティスト名がaccumの中にあるか検索
const element = accum.find((item) => {return item.artist === current.artist});
//あったらカウントだけする
if(element){ element.count ++}
//なかったらaccumに追加してあげる
else{
accum.push({
artist: current.artist,
count: 1
});
}
return accum
}, []);
console.log(summary)
↓
[ { artist: 'あいみょん', count: 3 },
{ artist: 'ONE OK ROCK', count: 1 },
{ artist: 'エド・シーラン', count: 1 } ]
reduceは集約するときに使う感じですね。forEachで足していくほうがわかりやすいんですけどreduceが使えたらかっこいいなと。まだまだ慣れません。
おわりに
reduceはやはり小難しい。あいみょんすごい。もう少し追記していきたいと思っているところです。