JavaScriptの疎な配列

JavaScript の疎な配列とは?

JavaScript の配列では、必ずしも 0 から始まる連続したインデックスに対応する要素を持つ必要がありません。

例えば、次のようにカンマで区切った箇所 (スロット) に要素を指定しない場合、そのインデックスに対応する箇所は空 (empty) のままになります。

const a = [, , , 'Hello', ,]
console.log(a) // [ <3 empty items>, 'Hello', <1 empty item> ]
console.log('a.length:', a.length) // a.length: 5

この例では配列の長さは 5 ですが、要素は a[3] のひとつ (値は 'Hello') しか割り当てられていません。

配列リテラルで要素を記述する時、最後の要素の後のカンマは任意です。このため ['A']['A',] はどちらも 'A' という文字要素ひとつの配列['A']を表します。

最後のカンマの後には、空の要素があるとはみなされません。従って [, ,][ <2 empty items> ] のことであり、 [,][ <1 empty item> ] です。

Object.keys() メソッドを使うと、要素が割り当てられた箇所のインデックス (の文字列) の配列が取得できます。

const indices = Object.keys(a)
console.log(indices) // [ '3' ]
if (indices.length < a.length) {
  console.log('It is a sparse array.') // It is a sparse array.
} else {
  console.log('It is a dense (normal) array.')
}

この例では確かに、インデックス 3 にのみ要素が割り当てられていることがわかります。

このように、「配列の長さより少ない数の要素しか持たない配列」を疎な配列 (sparse array) といいます。 それに対して、配列の長さと同じ数の要素を持ついわば「通常の」配列は、「密な配列」 (dense array) ということがあります。

念のため言うと、「空」(empty) はあくまでも空っぽです。undefined が割り当てられている、というわけではありません。しかし、空のスロットの値を取得すると、未割り当てであるため undefined として取得されます。

console.log(a[1]) // undefined

JavaScript の疎な配列の作成

疎な配列を作るには上で見たように、配列リテラルで要素を指定しない (カンマだけ記述する) 方法があります。

その他、 Array() コンストラクタに長さを指定すると、指定した長さをもつ疎な配列が作成されます。

const a = new Array(3)
console.log(a) // [ <3 empty items> ]

さらに、既存の配列の要素数を超えた範囲のインデックスに要素を割り当てると、中抜けになった箇所は空の要素となります。

const a = [1, 2, 3]
a[5] = 'Hello'
console.log(a) 
// [ 1, 2, 3, <2 empty items>, 'Hello' ]

JavaScript の疎な配列のインデックスの取得

上でも書きましたが、 Object.keys() 関数を使うことで配列の要素が割り当てられている箇所のインデックスの配列が取得できます。

const a = [1, 2, 3]
a[5] = 'Hello'
console.log(Object.keys(a)) 
// [ '0', '1', '2', '5' ]

インデックスは数値ですが、文字列の配列として取得できます。

一方、 Array の keys() メソッドは配列のインデックスを、 0 から配列の長さ分だけ列挙するイテレータを返します。

const a = [, , , 'Hello', ,]
for (const k of a.keys()) {
  console.log(k, a[k])
}
// 0 undefined
// 1 undefined
// 2 undefined
// 3 Hello
// 4 undefined

JavaScript の疎な配列に対する map 関数の適用

疎な配列に対して map 関数を適用すると、コールバック関数は存在する要素に対してのみ呼ばれます。 しかし、返される配列は元の配列と同じインデックスが空の疎な配列になります。

次の例では、map 関数のコールバック関数は2回しか呼ばれていませんが、 map 関数が返す配列も疎な配列になります。

const a = [, 5, , , 7, ,]
const b = a.map((val, idx) => {
  console.log(`* ${idx}:${val}`)
  return val * val
})
console.log(b)
console.log(Object.keys(b))
// * 1:5
// * 4:7
// [ <1 empty item>, 25, <2 empty items>, 49, <1 empty item> ]
// [ '1', '4' ]

JavaScript の疎な配列に対するスプレッド構文の適用

疎な配列に対してスプレッド構文を適用すると、空の要素は undefined として展開されます。

その結果として、元の配列の長さの要素を持つ密な配列が作成されます。

const a = [, , 'A', ,]
console.log('a', a)
console.log('a', Object.keys(a))
const b = [...a]
console.log('b', b)
console.log('b', Object.keys(b))
// a [ <2 empty items>, 'A', <1 empty item> ]
// a [ '2' ]
// b [ undefined, undefined, 'A', undefined ]
// b [ '0', '1', '2', '3' ]

以上、JavaScript の疎な配列について説明しました。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 JavaScript 入門