JavaScriptでPython風のzip_longest関数を実装する
こちらの記事でPython風のzip関数を実装しました。
今回はzip_longest
関数を作成します。以下のように、各配列の同じインデックスの要素をまとめます。
const a1 = [1, 2, 3] const a2 = ["Jan", "Feb", "Mar"] const a3 = ["Garnet", "Amethyst", "Aquamarine"] zip_longest(a1, a2, a3) #=> [[1, "Jan", "Garnet"], [2, "Feb", "Amethyst"], [3, "Mar", "Aquamarine"]]
各配列の長さが異なる場合には、一番長い配列の長さになります。未定義値はundefined
になります。
const a1 = [1, 2, 3, 4] const a2 = ["Jan", "Feb", "Mar", "Apr", "May"] const a3 = ["Garnet", "Amethyst", "Aquamarine"] zip_longest(a1, a2, a3) #=> [[1, "Jan", "Garnet"], [2, "Feb", "Amethyst"], [3, "Mar", "Aquamarine"], [4, "Apr", undefined], [undefined, "May", undefined]]
zip_longest関数本体
zip_longest関数の実装です。
const zip_longest = (...arrays) => { const length = Math.max(...(arrays.map(arr => arr.length))) return new Array(length).fill().map((_, i) => arrays.map(arr => arr[i])) }
コードの解説
ほとんどzip
関数の解説と同じです。
まず、関数の定義の部分を解説します。レスト構文を使用して、引数全てをarrays
に格納します。
const zip_longest = (...arrays) => { }
例えば、
const a1 = [1, 2, 3, 4] const a2 = ["Jan", "Feb", "Mar", "Apr", "May"] const a3 = ["Garnet", "Amethyst", "Aquamarine"] zip_longest(a1, a2, a3)
と呼び出したとき、arrays
は
[ [1, 2, 3, 4], ["Jan", "Feb", "Mar", "Apr", "May"], ["Garnet", "Amethyst", "Aquamarine"] ]
です。以下、引数にこの配列を渡したときの動作を説明します。
zip_longest
関数では、一番長い配列の長さに合わせるので、まず一番長い配列の長さを求めます。
まず、各配列の長さを、求めます。
const zip_longest = (...arrays) => { arrays.map(arr => arr.length) #=> [4, 5, 3] }
この中の最大値は、Math.maxとスプレッド演算子を使用して、以下のように書けます。
const zip_longest = (...arrays) => { const length = Math.max(...(arrays.map(arr => arr.length))) #=> const length = Math.max(...[4, 5, 3]) #=> const length = Math.max(4, 5, 3) #=> const length = 5 }
5回繰り返すので、new Array(length).fill().map((_, i) => i)
の構文を使用します。
const zip_longest = (...arrays) => { const length = Math.max(...(arrays.map(arr => arr.length))) new Array(length).fill().map((_, i) => i)) #=> [0, 1, 2, 3, 4] }
fill
をはさむ理由については、こちらの記事をご覧ください。
各配列のi
番目の要素は、
arrays.map(arr => arr[i])
で取得することができます。よくわからない場合は、i
ではなく、0
、1
、2
など具体的な数字で考えるとよいです。例えば、各配列の0番目の要素は、
arrays.map(arr => arr[0]) #=> [1, "Jan", "Garnet"]
です。
これをmap
に渡す関数の戻り値にします。
JavaScriptの場合、配列の長さより大きいインデックスを指定した場合はundefined
になります。
const zip_longest = (...arrays) => { const length = Math.max(...(arrays.map(arr => arr.length))) return new Array(length).fill().map((_, i) => arrays.map(arr => arr[i])) #=> [[1, "Jan", "Garnet"], [2, "Feb", "Amethyst"], [3, "Mar", "Aquamarine"], [4, "Apr", undefined], [undefined, "May", undefined]] }
以上でzip_longest
関数の完成です。
補足的な話題はzip関数の方の記事に記載していますので、あわせてご覧ください。