reduceって何?
reduceとはArrayが持つメソッド
使い方は?
["a", "b"]配列に対して
["a", "b"].reduce(f, initValue)このように使います。
fは関数です。
initValueは初期値です
配列の中身、この場合
aと b
に対して
f
で書かれたことを (初期値を渡さない場合)要素数-1だけ実行します
ちょっと実際やってみましょう
const strArray = ["a", "b", "c"] // 配列
const a = strArray.reduce((a, c) => a + c)
a // "abc"何が起きたのでしょうか
const a = strArray.reduce((p, c) => p + c)reduceに渡している
(p, c) => p + cは関数です
これは p + c
をして結果を返しています
const f = (p, c) => p + c
const a = strArray.reduce(f)先ほどの例題と同じになりました
reduceの第二引数に初期値は渡してません
reduceに渡してたfはstrArrayの
(初期値を渡さない場合)要素数-1だけ実行します
const strArray = ["a", "b", "c"] // "a" "b" "c"が入っているので
const f = (p, c) => p + c // 2(3-1)回これが実行される
const a = strArray.reduce(f) // 初期値は渡していない
1回目
const f = ("a", "b") => "a" + "b"
const a = strArray.reduce(f)
2回目
const f = ("ab", "c") => "ab" + "c"
const a = strArray.reduce(f)
a // "abc"
になります
ここでreduceの構文をみましょう
reduceのfには
const f = (p, c, i, a) => {}4つの引数が渡ってきます(先ほどはiとaを使いませんでした)、
それぞれ、
p(前回の値), c(現在の値), i(インデックス), a(配列) // それぞれprevious, current, index, arrayの略ですです。
これらを使って値を返します。(ここら辺は実際に手を動かしてまた後ほど話します)
今はreduceの第一引数に渡した関数から4つの仮引数が渡ってくるんだと覚えておいてください
["a", "b"].reduce(f, initValue)
の
reduceメソッドの第二引数に渡すinitValueとはなんでしょう。
これは
reduceが最終的に返す型で
最初にfのpに渡ってくる型です
initValueを省略することもできます。
["a", "b"].reduce(f)
その場合
aに渡ってくるのは
["a", "b"].reduce(f)"a"です
initValueを指定する場合と指定しない場合で動きが変わることに注意です。ここが大事です
- initValueを指定した場合
- 最初の
pにはその値が渡ってきます
- 最初の
initValueを指定しない場合- 最初の
pには配列の最初の要素が渡ってきます
- 最初の
でどんな時使うの?
- 配列に入っている要素を違う型に変更して返したいとき
型ってなぁに
- 簡単にいうとデータ構造の形
型とは
例えば
"a"はstring
ですね。
では
1は?
number
です。
stringとnumberでは使えるメソッドも違います。型が違うからです。
型とはわかりやすくいうと
生まれてきた親が違うと思っておいてください
stringは
const a = "a" // ここで`string`として生まれました。以降aに入っているのは`stringですconst b = 1 // ここでnumberとして生まれました。以降bに入っているのは`numberですtypeof a // "string"
typeof b // "number"
簡単にいうとこれが型です。
では配列はどうでしょう
配列の型は
[]
のように表現します
const c = [] // 配列として生まれたオブジェクトは?
{}です。
const d = {} // オブジェクトとして生まれたではこちら
["a", "b"]こちらは型としてどう表現したらいいと思いますか?
配列にstring型が入っています
配列に入っている要素がstring型の場合を型で示す時はこのように表現します
string[]
じゃあこれは?
[1, 2]配列に入っている要素がnumber
number[]
です。
配列[]に入っているのはnumber型だからです。
ではこれはどうでしょう。
[{id: 1, name: "a"}]
型としてはどういう表現になるでしょう
{id: number, name: string}[]
型としてはこのような表現になります。
idとnameのプロパティはそれぞれ1というnumber、
nameは"a"というstringを持った、
オブジェクト型(誤解が生じやすいところです)です。
これが配列の要素になっています。
これはどうでしょう。同じ形のプロパティの型は同じですが違う値です。
[{id: 1, name: "a"}, {id: 2, name: "b"}]これも型で表現する場合同じです
{id: number, name: string}[]
です。
だんだん型が何かわかってきましたか。じゃあ、
{id: 1, name: "a", friends: ["b", "c", "d"]}はどうでしょう。
ある構造(ここではidやnameプロパティを持った)をしているオブジェクトにfriendsはstringを要素にもつ配列を持っています。
型としてはどのような表現になるでしょう
{id: number, name: string, friends: string[]}ですね。
では本題です
reduceを使いたいとき
- 配列に入っている要素を違う型に変更して返したいとき
とは...
const strArray = ["a", "b", "c"] // 配列
const a = strArray.reduce((a, c) => a + c)
a // "abc" // string[] -> string// string[] が stringとして返ってきました
number[]はどうでしょう
const numrrArray = [1, 2, 3]
const b = numrrArray.reduce((a, c) => a + c)
b // 6 1,2,3を全て足して6として返りました
つまり
number[]がnumber
[{id: 1, name: "a"}, {id: 2, name: "b"}]の型は
{id: number, name: string}[]これを
{1: {id: 1, name: "a"}, 2: {id: 2, name: "b"}}にするには
const c = [{id: 1, name: "a"}, {id: 2, name: "b"}]
c.reduce((a, c) => {
return {...a, [c.id]: c}
}, {})
c // {1: {id: 1, name: "a"}, 2: {id: 2, name: "b"}}一気に難しくなりました
const arr = [{eee: "kenji", value: "22"}, {aa: "keiko", value: "30"}]
arr.reduce((a, n, i) => {
a["key"] = [...a["key"] || [], Object.keys(n)[0]]
a["value"] = [...a.value || [], n.value]
return a
}, {})[10, 30, 2000].reduce((a, n, i, arr) => {
if(i === arr.length -1){
const result = a + n
return result / 2
}
return a + n
})