練習問題(解答付き) — indexOf / lastIndexOf をしっかり練習しよう
以下は初心者〜中級者向けの練習問題(合計8問)。各問題に「問題」「期待される出力」「解答コード」「解説」「よくある間違い」を付けています。自分でまず考えてから答えを確認してください。
初級:問題1
問題
配列 ['cat','dog','rabbit','dog'] の中で、dog の最初の出現位置と最後の出現位置をコンソールに出力しなさい。
期待される出力
1
3
解答コード
const animals = ['cat','dog','rabbit','dog'];
console.log(animals.indexOf('dog')); // 1
console.log(animals.lastIndexOf('dog')); // 3
JavaScript解説indexOf は左(先頭)から見つかる最初のインデックス、lastIndexOf は右(末尾)から見つかる最初=配列全体で最後に現れる位置を返す。配列は 0 始まりなので 'dog' は 1 と 3。
よくある間違い
indexOfとlastIndexOfの意味が逆になってしまう(頭と末尾を取り違える)。- インデックスが 1 始まりだと勘違いする。
初級:問題2
問題
配列 [5,3,5,7,3] に 3 が存在するかを調べ、あれば "ある", なければ "ない" を出力しなさい。(indexOf を使うこと)
期待される出力
ある
解答コード
const arr = [5,3,5,7,3];
console.log(arr.indexOf(3) !== -1 ? 'ある' : 'ない');
JavaScript解説indexOf が見つからないと -1 を返すので、!== -1 のチェックで存在確認ができる(includes を使えばより直感的)。
よくある間違い
if (arr.indexOf(3))のように書いてしまうと、indexOfが0のとき false 扱いになって誤判定になる。
初級:問題3
問題
配列 ['a','b','a','c','b'] から重複を取り除き [ 'a','b','c' ] にするコードを filter と indexOf だけで書きなさい。
期待される出力
['a','b','c']
解答コード
const arr = ['a','b','a','c','b'];
const uniq = arr.filter((v, i, self) => self.indexOf(v) === i);
console.log(uniq); // ['a','b','c']
JavaScript解説filter のコールバックで「その要素が配列で最初に出現する位置(indexOf(v))」と現在のインデックス i を比較する。等しければ初出なので残す。
よくある間違い
indexOfをarr.indexOf(v)と書くが、filter内で参照する配列は第三引数selfを使した方が汎用的(現状はarrでも動く)。
中級:問題4
問題
配列 ['x','y','x','z'] から最初に出てくる 'x' を削除して、結果の配列を出力しなさい。(indexOf と splice を使うこと)
期待される出力
['y','x','z']
解答コード
const arr = ['x','y','x','z'];
const idx = arr.indexOf('x');
if (idx !== -1) arr.splice(idx, 1);
console.log(arr); // ['y','x','z']
JavaScript解説indexOf で削除したい要素のインデックスを取得し、それを splice(index, 1) で消す。splice は配列を直接変更する(破壊的操作)。
よくある間違い
sliceと混同してslice(idx, 1)と書いてしまう(sliceは破壊しないし引数の意味が違う)。
中級:問題5
問題
配列 [1,2,3,2,1] の中で 2 が最後に出てくる位置(インデックス)を求め、その位置以降(その要素も含めて)を新しい配列として切り出しなさい。(lastIndexOf と slice を使う)
期待される出力
[2,1]
解答コード
const arr = [1,2,3,2,1];
const idx = arr.lastIndexOf(2);
const result = idx !== -1 ? arr.slice(idx) : [];
console.log(result); // [2,1]
JavaScript解説lastIndexOf で最後の 2 の位置(この場合 3)を取得し、slice(3) でそのインデックスから末尾までを切り出す。slice は非破壊で新しい配列を返す。
よくある間違い
lastIndexOfの第2引数の意味を誤解してlastIndexOf(2, 1)のように書き、期待通りに見つからないことがある。
中級:問題6(実用)
問題
配列 ['red','green','blue'] に 'green' があるなら削除して、なければ 'green' を先頭に追加する処理を書きなさい(indexOf と splice / unshift を使う)。
期待される出力(初期配列の場合)
['red','blue'] // 'green' を見つけて削除した結果
解答コード
const colors = ['red','green','blue'];
const idx = colors.indexOf('green');
if (idx !== -1) {
colors.splice(idx, 1); // 見つかれば削除
} else {
colors.unshift('green'); // 見つからなければ先頭に追加
}
console.log(colors);
JavaScript解説indexOf で存在チェック→存在すれば splice で削除、存在しなければ unshift(先頭追加)で挿入。実用ではトグル(存在なら削除、なければ追加)としてよく使う。
よくある間違い
splice(idx)と引数を1つだけ指定してしまい、以降すべての要素を削除してしまう(削除数を必ず指定する)。
上級:問題7(応用)
問題
オブジェクトの配列 [{id:1},{id:2},{id:1}] がある。id === 1 を持つ最初のオブジェクトのインデックスを取得しなさい。ただし indexOf は使えない(ヒント:findIndex を使うと簡単)。
期待される出力
0
解答コード
const list = [{id:1},{id:2},{id:1}];
const idx = list.findIndex(item => item.id === 1);
console.log(idx); // 0
JavaScript解説indexOf はオブジェクトを参照で比較するため、中身だけで探せない。findIndex にコールバックを渡して条件(item.id === 1)を指定すると便利。findIndex は該当要素のインデックスを返す(見つからなければ -1)。
よくある間違い
indexOf({id:1})としてしまう(常に -1 になるケースが多い)。
上級:問題8(トリッキー)
問題
配列 [NaN, 1, 2] の中に NaN が含まれるかを判定し、含まれていれば "NaNあり" と出力しなさい。indexOf は使わないでください(理由は説明を読むこと)。
期待される出力
NaNあり
解答コード(推奨)
const arr = [NaN, 1, 2];
if (arr.includes(NaN)) {
console.log('NaNあり');
} else {
console.log('NaNなし');
}
JavaScript代替解(ES5以前や includes が無い環境向け)
const arr = [NaN, 1, 2];
const hasNaN = arr.some(v => Number.isNaN ? Number.isNaN(v) : v !== v);
console.log(hasNaN ? 'NaNあり' : 'NaNなし');
JavaScript解説NaN === NaN は false なので indexOf(NaN) は見つけられない(-1 を返す)。ES6 の includes は NaN を正しく検出する。ポリフィルや some + Number.isNaN / v !== v(NaN だけ自分と等しくない性質を利用)で対応できる。
よくある間違い
indexOf(NaN) !== -1でチェックしてしまい見つけられないことに驚く。
最後に:練習のコツ
- まずは紙に配列のインデックス(0,1,2…)を書いて手で追ってみると挙動が分かりやすくなります。
indexOfはプリミティブ(文字列・数値など)向け、オブジェクト検索や条件検索はfindIndex/findを使うと楽。- 存在チェックは
indexOf(x) !== -1かincludes(x)のどちらか。includesのほうが読みやすくNaNも扱える。
