#目的
- 今回特に知りたいのは、多次元配列を処理後返ってくる配列要素の一つ一つの大きさである。
#今日やること
多次元ポケモンの配列に対して、MaxCpの合計値を出す。
ただし、値の入っていないポケモンがいます。
ポケモンが格納されているデータは、こんな感じ。(1匹分)
これが245匹分ある。
(() => {
window.allPokemon = [{
"Number": "001",
"Name": "Bulbasaur",
"Generation": "Generation I",
"About": "Bulbasaur can be seen napping in bright sunlight. There is a seed on its back. By soaking up the sun's rays, the seed grows progressively larger.",
"Types": [
"Grass",
"Poison"
],
"Resistant": [
"Water",
"Electric",
"Grass",
"Fighting",
"Fairy"
],
"Weaknesses": [
"Fire",
"Ice",
"Flying",
"Psychic"
],
"Fast Attack(s)": [{
"Name": "Tackle",
"Type": "Normal",
"Damage": 12
},
{
"Name": "Vine Whip",
"Type": "Grass",
"Damage": 7
}
],
"Special Attack(s)": [{
"Name": "Power Whip",
"Type": "Grass",
"Damage": 70
},
{
"Name": "Seed Bomb",
"Type": "Grass",
"Damage": 40
},
{
"Name": "Sludge Bomb",
"Type": "Poison",
"Damage": 55
}
],
"Weight": {
"Minimum": "6.04kg",
"Maximum": "7.76kg"
},
"Height": {
"Minimum": "0.61m",
"Maximum": "0.79m"
},
"Buddy Distance": "3km (Medium)",
"Base Stamina": "90 stamina points.",
"Base Attack": "118 attack points.",
"Base Defense": "118 defense points.",
"Base Flee Rate": "10% chance to flee.",
"Next Evolution Requirements": {
"Amount": 25,
"Name": "Bulbasaur candies"
},
"Next evolution(s)": [{
"Number": 2,
"Name": "Ivysaur"
},
{
"Number": 3,
"Name": "Venusaur"
}
],
"MaxCP": 951,
"MaxHP": 1071
},
配列からキーのみを抽出したり、値が入っている配列のみを取り出すのでmapやfilterの利用を検討。
ただ、その時に、配列の一つ一つの要素は、pokemonなのか、pokemon.MaxCPなのか、予測がつかなかったことを解決する。
#map
戻り値の配列の要素数は変わらず、コールバック関数内の処理をして変形(場合によってはより小さい要素になる)。
arr.map(function callback( currentValue[, index[, array]]) {
}[, thisArg])
例)allPokemonから各PokemonのMaxCPの配列を取得したいとき
//オブジェクトからキーのみ取り出す
const hasMaxCP = allPokemon.map(pokemon => {
return pokemon.MaxCP
});
//->[100,200,300,400・・・]
//MaxCPのみの配列を取得
//pokemon名などの情報は含まれない
#filter
配列の要素数は変わる可能性がありコールバック関数がtrueの要素のみの配列を、渡された配列の要素と同じ形で返す。
arr.filter(callback(element[, index, [array]])[, thisArg])
例)allPokemonから各PokemonのMaxCPの有無を確認し、存在確認できたものだけをpokemonの形で返したいとき
allPokemon.filter(pokemon => pokemon.MaxCP)
//->[{MaxCP有pokemonオブジェクト}{MaxCP有pokemonのオブジェクト}・・・]
//MaxCPをもつpokemonが返される。
##最終的な答え
reduceの最初の値(第二引数のacc)の知識が必要かもしれない。
avgMaxCP()=>{
return allPokemon.filter(pokemon => pokemon.MaxCP)
.reduce((acc, pokemon) => acc + Number(pokemon.MaxCP),0)
}
filter処理後にMaxCPを持つポケモンになっている。
reduceに、上記のポケモンオブジェクトを要素にもつの配列を渡しているので、reduceの第二引数には0をいれる必要がある。そうしなければ、reduceのaccにオブジェクトが入り、NaNになってしまう。(2つめからはNumberで処理しているけれど、1つ目が処理できない)
リファクタリング前
avgMaxCP () => {
const hasMaxCP = allPokemon.map(pokemon => {
return pokemon.MaxCP
});
const a = hasMaxCP.filter(maxcp => {
return maxcp
});
let sum = a.reduce((acc, cur) => {
return acc + cur
});
return sum
},
map処理後に、全てのポケモンをMaxCPに変形した。[1,2,3,undefined・・・]のイメージ。
(ポケモンのオブジェクトではない)
filterに上記の配列を渡して処理し、MaxCPをもつ要素だけの配列になる。
今、aには数字のみが入っているので、Numberやreduceの第二引数のような処理は不要になる。
reduceの処理については後日。