JavaScript の配列の操作まとめ
JavaScript の配列の基本的な操作方法についてまとめました。
仕事で JavaScript (以下 JS )でコードを書く機会があるのですが、触る頻度が低いため基本的な処理の仕方を覚えて忘れてまた覚えてを繰り返しています。 特に配列については他の言語でも使い方が似ていることもあってなかなか覚えられません。 何度も調べていて効率が悪いので JS の配列の使い方についてまとめておきます。
この記事では原則 主要ブラウザと Node.js の 2023 年の最新バージョンで使える というのを基本ルールとしています。
追記 2023/01/18: 2019 年 9 月の投稿でしたが、 2023 年 01 月に更新しました。
目次
- 生成
- オブジェクト化
- 要素数の確認
- 要素の参照
- 要素の代入
- ループ
- 要素の追加
- 要素の取り出し
- 配列を破壊しない要素の取り出し
- 要素の削除
- 要素が含まれるかどうかの判定
- 要素のインデックスの取得
- 条件を満たす要素の取得
- 要素のスライス
- ソート
- マップ
- フィルタ
- 畳み込み
- その他
生成
配列を生成するには []
を使用します。
var a1 = [3, 4, 5];
a1 instanceof Array;
// => true
Array.isArray(a1);
// => true
iterable をもとに配列を生成するには Array.from()
を使用します。
var a1 = Array.from('Hello');
// => [ 'H', 'e', 'l', 'l', 'o' ]
object から配列を生成する方法には Object.keys()
Object.values()
Object.entries()
があります。
var o1 = {'北': 'North', '南': 'South'};
Object.keys(o1)
// => [ '北', '南' ]
Object.values(o1)
// => [ 'North', 'South' ]
Object.entries(o1)
// => [ [ '北', 'North' ], [ '南', 'South' ] ]
オブジェクト化
配列からオブジェクトを生成するには Object.fromEntries()
を使用します。
var a1 = [
['北', 'North'],
['南', 'South'],
];
Object.fromEntries(a1)
// => { '北': 'North', '南': 'South' }
要素数の確認
要素数の確認には .length
を使用します。
var a1 = [100, 99, 98];
a1.length;
// => 3
要素の参照
要素の参照には []
を使用します。
インデックスは 0
始まりです。
var a1 = ['クライミング', 'ラフティング', 'カヤック'];
a1[0];
// => 'クライミング'
a1[1];
// => 'ラフティング'
a1[2];
// => 'カヤック'
a1[3];
// => undefined
追記 2023/01/18: 負数のインデックスで末尾から辿りたいときは .at()
が使えます。
var a1 = ['クライミング', 'ラフティング', 'カヤック'];
a1.at(0);
// => 'クライミング'
a1.at(-1);
// => 'カヤック'
a1.at(-2);
// => 'ラフティング'
a1.at(-3);
// => 'クライミング'
a1.at(-4);
// => undefined
.at()
は比較的最近導入されたものです。
.at()
が使えるようになる前は、負のインデックスで要素アクセスしたいときは Proxy
オブジェクトで Array
をラップして使うなどする必要がありました。
var handler = {
get(obj, prop) {
const index = Number(prop);
if (Number.isInteger(index)) {
if (index >= 0) {
return obj[index];
} else {
return obj[obj.length + index];
}
}
},
set(obj, prop, newval) {
const index = Number(prop);
if (Number.isInteger(index)) {
if (index >= 0) {
obj[index] = newval;
} else {
obj[obj.length + index] = newval;
}
}
}
};
var a1 = ['クライミング', 'ラフティング', 'カヤック'];
var a1plus = new Proxy(a1, handler);
a1plus[-1];
// => 'カヤック'
a1[-2];
// => 'ラフティング'
a1[-3];
// => 'クライミング'
a1[-2] = 'サイクリング';
a1;
// => [ 'クライミング', 'サイクリング', 'カヤック' ]
要素の代入
要素の代入には参照と同じ []
を使用します。
var a1 = ['マイカル', '平和堂'];
a1[0] = 'イオン';
a1;
// => [ 'イオン', '平和堂' ]
ループ
配列のループにはいくつかの方法があります。
ひとつめの方法は for
ループを使った方法です。
for
ループには次のいくつかのパターンがあります。
for (;;)
:
// for + インデックス
var a1 = ['パンダ', 'キリン', 'ライオン'];
for (let i = 0; i < a1.length; i++) {
console.log(a1[i]);
}
// =>
// 'パンダ'
// 'キリン'
// 'ライオン'
for .. in
:
// for .. in
// インデックスでのループになる
var a1 = ['パンダ', 'キリン', 'ライオン'];
for (let i in a1) {
console.log(a1[i]);
}
// =>
// 'パンダ'
// 'キリン'
// 'ライオン'
for .. of
:
// for .. of
// 値でのループになる
var a1 = ['パンダ', 'キリン', 'ライオン'];
for (let item of a1) {
console.log(item);
}
// =>
// 'パンダ'
// 'キリン'
// 'ライオン'
インデックスと値を同時に取得したい場合には for .. of
に entries()
メソッドを組み合わせるやり方があります。
// for .. of と entries() の併用
var a1 = ['パンダ', 'キリン', 'ライオン'];
for (let [index, item] of a1.entries()) {
console.log(index, item);
}
// =>
// 0 'パンダ'
// 1 'キリン'
// 2 'ライオン'
もうひとつの方法は配列の forEach()
メソッドを使った方法です。
// forEach
var a1 = ['パンダ', 'キリン', 'ライオン'];
// 値のみを使用する
a1.forEach(item => { console.log(item); });
// =>
// 'パンダ'
// 'キリン'
// 'ライオン'
// 値とインデックスの両方を使用する
a1.forEach((item, i) => { console.log(item, i); });
// =>
// 'パンダ' 0
// 'キリン' 1
// 'ライオン' 2
要素の追加
要素の追加は、追加したい位置によって push()
・ unshift()
・ splice()
を使い分けます。
- 末尾:
push()
- 先頭:
unshift()
- 途中:
splice()
push()
は次の形で使用します。
戻り値は要素追加後の要素数です。
var a1 = ['ラクダ', 'ダチョウ'];
a1.push('ウシ');
// => 3
a1;
// => [ 'ラクダ', 'ダチョウ', 'ウシ' ]
push()
には複数の要素を渡すこともできます。
var a1 = ['ラクダ', 'ダチョウ'];
a1.push('ウシ', 'シマウマ');
// => 4
a1;
// => [ 'ラクダ', 'ダチョウ', 'ウシ', 'シマウマ' ]
...
構文と組み合わせると、他の配列の要素をすべて追加することもできます。
var a1 = ['ラクダ', 'ダチョウ'];
var a2 = ['ウシ', 'シマウマ'];
a1.push(...a2);
// => 4
a1;
// => [ 'ラクダ', 'ダチョウ', 'ウシ', 'シマウマ' ]
unshift()
は次の形で使用します。
戻り値は要素追加後の要素数です。
var a1 = ['ウシ', 'シマウマ'];
a1.unshift('ラクダ', 'ダチョウ');
// => 4
a1;
// => [ 'ラクダ', 'ダチョウ', 'ウシ', 'シマウマ' ]
splice()
は次の形で使用します。
戻り値は取り除かれた要素からなる配列です。
var a1 = ['ラクダ', 'シマウマ'];
var start = 1;
var deleteCount = 0;
a1.splice(start, deleteCount, 'ダチョウ', 'ウシ');
// => []
a1;
// => [ 'ラクダ', 'ダチョウ', 'ウシ', 'シマウマ' ]
slice()
は slice(start, deleteCount, item1, item2, ...)
という形で使用します。
第一引数 start
は挿入位置のインデックス、第二引数 deleteCount
は元の配列から取り除く要素の数です。
今回のように単純に挿入するだけの場合は deleteCount
は 0
にします。
要素の取り出し
要素の取り出し(=インデックスを使った要素の削除)は、取り出したい要素の位置によって pop()
・ shift()
・ splice()
を使い分けます。
- 末尾:
pop()
- 先頭:
shift()
- 途中:
splice()
pop()
は次の形で使用します。
戻り値は取り出した要素の値です。
var a1 = ['あんぱん', 'ジャムパン', 'ピーナツバターパン'];
a1.pop();
// => 'ピーナツバターパン'
a1;
// => [ 'あんぱん', 'ジャムパン' ]
shift()
は次の形で使用します。
戻り値は取り出した要素の値です。
var a1 = ['あんぱん', 'ジャムパン', 'ピーナツバターパン'];
a1.shift();
// => 'あんぱん'
a1;
// => [ 'ジャムパン', 'ピーナツバターパン' ]
splice()
は次の形で使用します。
戻り値は取り除かれた要素からなる配列です。
var a1 = ['あんぱん', 'ジャムパン', 'ピーナツバターパン'];
var start = 0;
var deleteCount = 2;
a1.splice(start, deleteCount);
// => [ 'あんぱん', 'ジャムパン' ]
a1;
// => [ 'ピーナツバターパン' ]
配列を破壊しない要素の取り出し
元の要素を破壊せずに要素を取り出すには、アンパッキングの記法を使用します。
var a1 = ['H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne'];
var [first] = a1;
first;
// => 'H'
var [first, second] = a1;
first;
// => 'H'
second;
// => 'He'
スプレッド構文( ...
)を組み合わせると、残りの要素をすべて格納した配列を得ることができます。
var [first, second, ...rest] = a1;
rest;
// => [ 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne' ]
要素の削除
要素を削除する場合は、対象のどのように指定したいかによって使用すべきメソッドが異なります。
インデックスで指定したい場合は splice()
を、値で指定したい場合は indexOf()
と splice()
の組み合わせた方法を使用します。
より汎用的な方法として filter()
を使ったアプローチもあります。
splice()
メソッドの使い方は上で説明しているので割愛します。
特定の値を削除するための、 indexOf()
と splice()
を組み合わせた方法は次のとおりです。
var a1 = ['バス', '新幹線', 'セグウェイ'];
var target = '新幹線';
var index = a1.indexOf(target);
if (index > -1) {
a1.splice(index, 1);
// => [ '新幹線' ]
}
a1;
// => [ 'バス', 'セグウェイ' ]
filter()
を使うと、より柔軟な形で要素の削除を行うことができます。
// 特定の値をすべて削除する
var a1 = ['バス', '新幹線', 'セグウェイ', '新幹線', 'バス'];
var target = '新幹線';
a1 = a1.filter(item => item !== target);
// => [ 'バス', 'セグウェイ', 'バス' ]
// インデックス指定で削除する
var a1 = ['バス', '新幹線', 'セグウェイ'];
var targetIndex = 1;
a1 = a1.filter((item, index) => index !== targetIndex);
// => [ 'バス', 'セグウェイ' ]
尚、キーワード delete
を使った方法でも配列の要素を削除することができますが、 delete
を使うと「 length
の値が削除前と変わらない」「インデックスに歯抜けが生じる」という少しトリッキーな挙動になります。
delete
は配列の要素の削除には使わないようにした方がよいです。
// delete を使って要素を削除すると...
var a1 = ['バス', '新幹線', 'セグウェイ'];
delete a1[1];
// '新幹線' が削除された
a1;
// => [ 'バス', <1 empty item>, 'セグウェイ' ]
// しかし length は 3 のまま
a1.length;
// => 3
// `Array.from()` で復元すると要素数は 3 の配列のまま
Array.from(a1.entries());
// => [ [ 0, 'バス' ], [ 1, undefined ], [ 2, 'セグウェイ' ] ]
要素が含まれるかどうかの判定
要素が含まれるかどうかを判定するには、条件指定の方法によって includes()
と some()
を使います。
要素の値を指定して判定する場合は includes()
を、条件を表す関数を渡して判定する場合は some()
を使います。
includes()
は次の形で使用します。
var a1 = ['太陽', '月', '金星'];
a1.includes('金星');
// => true
a1.includes('土星');
// => false
some()
は次の形で使用します。
var a1 = [
{en: 'Sun', ja: '太陽'},
{en: 'Moon', ja: '月'},
{en: 'Venus', ja: '金星'},
];
a1.some(item => item.en === 'Sun');
// => true
a1.some(item => item.en === 'Mercury');
// => false
尚、 some()
の兄弟のようなメソッドに every()
というものがあります。
some()
は配列の中に条件を満たす要素が 1 つでもあれば true
を返しますが、 every()
はすべての要素が条件を満たす場合にのみ true
を返します。
要素のインデックスの取得
特定の要素のインデックスを取得するには indexOf()
または findIndex()
を使用します。
要素の値を指定して判定する場合は indexOf()
を、条件を表す関数を渡して判定する場合は findIndex()
を使います。
indexOf()
は次の形で使用します。
戻り値は、一致する要素が見つかった場合はそのインデックス、見つからなかった場合は -1
です。
var a1 = ['花', '星', '雪'];
a1.indexOf('星');
// => 1
a1.indexOf('宙');
// => -1
findIndex()
は次の形で使用します。
戻り値のルールは indexOf()
と同じです。
var a1 = ['花', '星', '雪'];
a1.findIndex(item => ['光', '雪'].includes(item));
// => 2
a1.findIndex(item => ['氷', '土'].includes(item));
// => -1
条件を満たす要素の取得
条件を満たす要素を取得するには find()
を使用します。
find()
は次の形で使用します。
var a1 = [
{name: 'JavaScript', age: 24},
{name: 'Java', age: 24},
{name: 'Python', age: 28},
{name: 'Kotlin', age: 8},
{name: 'Swift', age: 5},
];
a1.find(item => item.age < 10);
// => { name: 'Kotlin', age: 8 }
尚、 find()
は条件に合致した最初の要素を返しますが、 filter()
は条件に合致した要素をすべて返します。
要素のスライス
要素のスライス(特定のインデックス区間の要素の取得)には slice()
を使用します。
var a1 = ['北海道', '青森', '山形', '岩手'];
var begin = 2;
var end = 3;
a1.slice(begin, end);
// => [ '山形' ]
slice()
では、要素のインデックスが begin
以上 end
未満の要素を含む配列が返されます。
slice()
は splice()
とは異なり、元の配列は破壊されません。
ソート
ソートには sort()
を使用します。
sort()
には比較のロジックを表す関数を渡します。
var a1 = [
{name: 'JavaScript', age: 24},
{name: 'Java', age: 24},
{name: 'Python', age: 28},
{name: 'Kotlin', age: 8},
{name: 'Swift', age: 5},
];
var comparator = (l, r) => {
if (l.age < r.age) {
return -1;
} else if (l.age > r.age) {
return 1;
}
return 0;
};
a1.sort(comparator);
// =>
// [
// { name: 'Swift', age: 5 },
// { name: 'Kotlin', age: 8 },
// { name: 'JavaScript', age: 24 },
// { name: 'Java', age: 24 },
// { name: 'Python', age: 28 }
// ]
尚、 sort()
に関数を渡さなかった場合は、各要素を文字列に変換した辞書順でソートされます。
これは数字を要素とした配列に使うと直感と異なる動きをするので注意が必要です。
var numbers = [3, 200, 5.5, -3.2, -3];
numbers.sort();
numbers;
// => [ -3, -3.2, 200, 3, 5.5 ]
マップ
マップ処理には map()
を使用します。
var a1 = [
{name: 'たこ'},
{name: 'いか'},
{name: 'さんま'},
{name: 'うなぎ'},
];
var names = a1.map(item => item.name);
// => [ 'たこ', 'いか', 'さんま', 'うなぎ' ]
フィルタ
フィルタ処理には filter()
を使用します。
var a1 = [
{title: 'たこ', date: new Date('2014-01-23')},
{title: 'いか', date: new Date('2015-10-15')},
{title: 'さんま', date: new Date('2019-06-27')},
{title: 'うなぎ', date: new Date('2020-08-10')},
];
var threshold = new Date('2018-05-27');
var freshers = a1.filter(item => item.date > threshold);
// =>
// [
// { title: 'さんま', date: 2019-06-27T00:00:00.000Z },
// { title: 'うなぎ', date: 2020-08-10T00:00:00.000Z }
// ]
畳み込み
畳み込み処理には reduce()
を使用します。
var lines = [
'一行が丘の上についた時、',
'彼等は、言われた通りに振返って、',
'先程の林間の草地を眺ながめた。',
'忽ち、',
'一匹の虎が草の茂みから道の上に躍り出たのを彼等は見た。',
];
lines.reduce((accum, item) => accum + ' / ' + item);
// =>
// '一行が丘の上についた時、 / 彼等は、言われた通りに振返って、 / 先程の林間の草地を眺ながめた。 / 忽ち、 / 一匹の虎が草の茂みから道の上に躍り出たのを彼等は見た。'
その他
整数のリストの生成
1 から指定された値までの整数を要素に含む配列を生成するには Array.from()
等を使用します。
/**
* 1 から指定された整数までを格納した配列を返す
*/
function range(stop) {
return Array.from({ length: stop }, (_, i) => i + 1);
}
range(0);
// => []
range(1);
// => [1]
range(5);
// => [1, 2, 3, 4, 5]
0 から指定された値未満の整数までを格納した配列を返す場合は次のようにします。
/**
* 0 から指定された整数までを格納した配列を返す(指定された値を含まない)
*/
function range0(stop) {
return Array.from({ length: stop }, (_, i) => i);
}
range0(0);
// => []
range0(1);
// => [0]
range0(5);
// => [0, 1, 2, 3, 4]
以上です。
今後必要に応じて改訂していこうと思います。