前回の記事、
4歳娘「パパ、20歳以上のユーザーを抽出して?」
の続きやで!
休日ワイ
ワイ「最近、コロナウィルスの影響でリモートワークがメインになってしもうたから」
ワイ「家でも快適にお仕事ができるように、42.5インチの特大モニタを買ったで!」
ワイ「やっぱデッカいモニタはええな〜」
ワイ「インデントも思いっ切り入れれるわ」
よめ太郎「さすがに入れすぎやろ・・・」
ワイ「私のインデントは53ですいうてな」
よめ太郎「いやフリーザ様どこで勝負してんねん」
よめ太郎「しかもインデント奇数なんかい」
娘(4歳)「ねえ、パパ?」
ワイ「ん?」
ワイ「なんや、娘ちゃん」
娘「その大きいモニタを使って、早速やってほしい作業があるの」
ワイ「おお、ええでええで!」
娘ちゃんの依頼内容
娘「実は、こないだ山で拾ってきた家族風オブジェクトに、子供が増えてて」
娘「オブジェクトの内容が変わっちゃったの」
const family = {
mother: {
name: "よめ太郎",
age: 35
},
father: {
name: "やめ太郎",
age: 37
},
children: [
{
name: "娘ちゃん",
age: 4
},
{
name: "ボブ",
age: 39
}
]
};
娘「daughterがchildrenになっちゃったの」
ワイ「ん?どういうことや?」
娘「前回は娘が1人だけだったからdaughterっていうオブジェクトだったけど」
娘「子供が1人増えて、childrenという配列になっちゃったの」
娘「だから、20歳以上のユーザーを上手く抽出できなくなっちゃったの」
ワイ「そ、そうなんか」
ワイ「でも、子供たちはどうせ20歳未満なんやから」
ワイ「motherとfatherだけ取り出せばええんちゃうの?」
娘「それが・・・弟のボブは養子で39歳なの」
ワイ「Oh...ボブ...」
ワイ「ワイの知らん間に子供が増えてるから、少しおかしいなって思ったけど」
ワイ「そういう事情やったんか」
ワイ「これは、ワイだけでは無理や」
ワイ「ハスケル子ちゃんを呼ぼう」
ハスケル子もTV会議で参戦
ワイ「もしもし、ハスケル子ちゃん?」
ハスケル子「はい」
ハスケル子「私を呼ぶってことは、ボブの件ですね」
ワイ「さすがハスケル子ちゃん、話が早いわ」
よめ太郎「(いや早すぎやろ)」
オブジェクトと配列が混ざっている件
ワイ「motherとfatherはオブジェクトなのに」
ワイ「childrenは配列やねん」
ワイ「オブジェクトと配列が混ざってんねん」
娘「そうなの」
娘「そこから、20歳以上のユーザーを抽出して」
娘「以下のようなotonaArrayっていう配列を作りたいの」
[
{
name: "よめ太郎",
age: 35
},
{
name: "やめ太郎",
age: 37
},
{
name: "ボブ",
age: 39
}
]
ハスケル子「うーん」
ハスケル子「オブジェクトと配列が混じってて扱いづらいなんて・・・」
ハスケル子「そもそも仕様とか設計の問題のような・・・」
ハスケル子「もっと、サーバサイドでデータを整形してから返したほうが・・・」
ワイ「いや、仕様とか設計とかサーバサイドとかじゃないねん」
ワイ「山で拾ったオブジェクトなんやから」
ワイ「もうボブは家族なんやから」
ハスケル子「やむを得ないですね」
ハスケル子「分かりました」
ハスケル子「大人だけを抽出したotonaArrayという配列を作ればいいんですね」
まずはObject.values()とmap()
ハスケル子「familyというオブジェクトを元に配列を作るので」
ハスケル子「まずはObject.values(family)ですね」
const familyArray =
Object.values(family)
ハスケル子「↑こうですね」
ハスケル子「オブジェクトのkey名は使わずにvalueだけ取り出して、配列を作ってくれるメソッドです」
ハスケル子「つまり、familyArrayの中身は・・・」
// familyArrayの中身
[
{ name: "よめ太郎", age: 35 },
{ name: "やめ太郎", age: 37 },
[
{ name: "娘ちゃん", age: 4 },
{ name: "ボブ", age: 39 }
]
]
ハスケル子「↑こんな風になります」
ワイ「おお、あとはこの中から20歳以上のユーザーを抽出すんねやな」
ワイ「でも、オブジェクトと配列が混じってるけど大丈夫なん?」
ハスケル子「余裕です」
ハスケル子「配列のflat()メソッドを使って」
ハスケル子「ネストした配列から1段階フラットな配列を作ります」
const flatFamilyArray =
familyArray.flat()
ハスケル子「↑こうですね」
ハスケル子「すると・・・」
// flatFamilyArrayの中身
[
{ name: "よめ太郎", age: 35 },
{ name: "やめ太郎", age: 37 },
{ name: "娘ちゃん", age: 4 },
{ name: "ボブ", age: 39 }
]
ハスケル子「↑こんな感じのflatFamilyArrayが出来上がります」
ワイ「おお」
ワイ「子供の配列が1段階フラットになって、単なるフラットな配列になってフラットやな!」
よめ太郎「(語彙どうなってんねん)」
ワイ「あとはfilter()で20歳以上のユーザーを抽出するだけやな・・・!」
ハスケル子「はい」
ハスケル子「なので、いちいち変数に入れずにまとめて書くと・・・」
const otonaArray =
Object.values(family)
.flat()
.filter(person => person.age >= 20);
ハスケル子「↑こうですね」
ハスケル子「すると・・・」
// otonaArrayの中身
[
{ name: "よめ太郎", age: 35 },
{ name: "やめ太郎", age: 37 },
{ name: "ボブ", age: 39 }
]
ハスケル子「↑こんな感じの、大人だけを集めたotonaArrayが出来あがります」
ワイ「まじか〜」
ワイ「flat()メソッド便利やな」
ハスケル子「はい」
ワイ「今までのワイやったらflat()メソッドなんて知らんかったから」
ワイ「Array.isArray()メソッドを使って」
ワイ「配列ならこう、配列じゃなければこう・・・みたいな感じで」
ワイ「if文とかで条件分岐しながら」
ワイ「配列の詰め直しをしとったところやわ」
ハスケル子「なるほど」
ハスケル子「つまり・・・」
// まず空配列を生成。
const flatFamilyArray = [];
familyArray.forEach(personOrArray => {
// if文で配列かどうか判断しながら詰め直していく。
if (Array.isArray(personOrArray)) {
// 配列の場合はスプレッドで展開してpush。
flatFamilyArray.push(...personOrArray);
} else {
// 配列じゃない場合はそのままpush。
flatFamilyArray.push(personOrArray);
}
});
ハスケル子「↑こういう感じで処理するってことですよね」
ワイ「せやせや」
ハスケル子「空配列を作って、そこにどんどん詰め直していく・・・」
ハスケル子「そういった、副作用と手続きの連続で書くのもまあ」
ハスケル子「分かりやすいといえば分かりやすいので良いんですけど」
ハスケル子「私はやっぱり」
const otonaArray =
Object.values(family)
.flat()
.filter(person => person.age >= 20);
ハスケル子「↑この、メソッドの連続で書ける関数型な感じが好きですね」
ワイ「なるほどなぁ・・・」
ワイ「flat()はなんか、if文を内包してるようで」
ワイ「魔法みたいやな」
ハスケル子「ちょっとそんな感じですよね」
ハスケル子「たとえば・・・」
[3].flat() // -> [3]
[[3]].flat() // -> [3]
ハスケル子「↑こんな感じで」
ハスケル子「元の値が3であろうと[3]であろうと」
ハスケル子「一度[]で包んでflat()してやれば」
ハスケル子「同じ[3]になる・・・」
ハスケル子「こういう型ハックみたいなの楽しいですよね」
ワイ「なるほどな」
ワイ「[3]をflat()しても、ただの3にはならないんやな」
ワイ「せやから[3].flat()してやることで型を合わせられる・・・」
ハスケル子「そうなんです」
ワイ「なるほどなぁ・・・」
ワイ「オブジェクトから配列に変換しつつ、フラットにして、フィルタリングする・・・」
ワイ「って一つの流れの中でできるから」
ワイ「なんかカッコええね」
ハスケル子「はい!」
まとめ
-
flat()はネストした配列を1段階フラットにしてくれる。
(引数を与えることで2段階、3段階フラットにすることも可能)
ワイ「↑こんな感じやね!」
ハスケル子「はい」
ハスケル子「今回みたく、オブジェクトと配列を同列に扱わないといけない、なんてのは」
ハスケル子「そもそも設計が微妙な感じもしますけど」
ハスケル子「例えば、スクレイピングで取得したデータとかの場合は」
ハスケル子「データの形式を自分で決められないので」
ハスケル子「こういうハックが役に立つこともあるかもしれませんね」
ハスケル子「もし思い出したら、使ってみてください」
ハスケル子「たまに便利ですよ!」
ワイ「なるほどな」
ハスケル子「もっと楽しい、flatMap()なんていうメソッドもありますよ」
ハスケル子「map()してflat()してくれるやつです」
ハスケル子「まるで関数が変身するみたいですよ」
ワイ「関数が変身する・・・?」
ワイ「どういうこと・・・?」
ハスケル子「それはまた次回お話しますね」
ワイ「おお、なんか楽しみやな・・・!」
〜つづく〜
続きはこちら
→ワイ「なに!?flatMap()で有給取り放題やと!?」
→4歳娘「パパ、そんなときはクロージャが役に立つんじゃない?」
参考文献
注意
もちろんIEでは使えへんから、Babelとか使ってな!