JavaScript Tips | 配列ユーティリティ:要素削除

JavaScript JavaScript
スポンサーリンク

何をしたいユーティリティか:「要素削除」

「要素削除」は、配列から特定の要素を取り除く処理です。
「このインデックスの要素を消したい」「この値を全部消したい」「条件に合うものだけ消したい」など、業務でめちゃくちゃよく出てきます。

ここで一番大事なのは、次の2点です。

元の配列を壊すか(破壊的)、壊さないか(非破壊的)を決めること。
「何を基準に削除するか」(インデックス・値・条件)をはっきりさせること。

業務ユーティリティとしては、基本は「非破壊」で書くのがおすすめです。


インデックス指定で削除する removeAt(非破壊)

基本の形

「この位置の要素を1つ消したい」という一番シンプルなパターンです。

function removeAt(array, index) {
  if (!Array.isArray(array)) {
    return [];
  }

  const len = array.length;
  if (index < 0 || index >= len) {
    return array.slice();
  }

  const head = array.slice(0, index);
  const tail = array.slice(index + 1);

  return [...head, ...tail];
}
JavaScript

重要ポイントの解説

まず Array.isArray で配列かどうかをチェックし、違ったら空配列を返します。
インデックスが範囲外(0 未満、または length 以上)の場合は、何も削除せずにコピーだけ返します。
slice(0, index) で「削除対象より前」、slice(index + 1) で「削除対象より後ろ」を取り出し、
[...head, ...tail] でつなげて「削除済みの新しい配列」を作ります。

元の配列は一切変更されません。

動作例

const arr = [10, 20, 30, 40];

const r1 = removeAt(arr, 1);  // 20 を削除
// [10, 30, 40]

const r2 = removeAt(arr, 0);  // 10 を削除
// [20, 30, 40]

const r3 = removeAt(arr, 10); // 範囲外 → そのままコピー
// [10, 20, 30, 40]

console.log(arr); // [10, 20, 30, 40](元は変わらない)
JavaScript

値で削除する removeValue / removeAll

最初に見つかった1件だけ削除する removeValue

「この値に一致する最初の1件だけ消したい」パターンです。

function removeValue(array, value) {
  if (!Array.isArray(array)) {
    return [];
  }

  const index = array.indexOf(value);
  if (index === -1) {
    return array.slice();
  }

  return removeAt(array, index);
}
JavaScript

indexOf で最初に見つかった位置を取り、見つからなければコピーだけ返します。
見つかったら removeAt を使って、その位置の要素を削除した新しい配列を返します。

動作イメージはこうです。

const arr = ["a", "b", "c", "b"];

const r1 = removeValue(arr, "b");
// ["a", "c", "b"](最初の b だけ削除)

const r2 = removeValue(arr, "x");
// ["a", "b", "c", "b"](見つからないのでそのまま)
JavaScript

一致するものを全部削除する removeAll

「この値に一致する要素を全部消したい」パターンです。

function removeAll(array, value) {
  if (!Array.isArray(array)) {
    return [];
  }

  return array.filter((item) => item !== value);
}
JavaScript

filter は「条件を満たすものだけ残す」ので、
「value と等しくないものだけ残す」=「value と等しいものを全部削除する」になります。

動作例:

const arr = ["a", "b", "c", "b"];

const r = removeAll(arr, "b");
// ["a", "c"]

console.log(arr); // ["a", "b", "c", "b"](元は変わらない)
JavaScript

条件で削除する removeIf(業務で一番使いやすい形)

predicate(条件関数)で削除対象を決める

業務では、「id が一致するものを消したい」「フラグが true のものだけ消したい」など、
単純な値一致ではなく「条件」で削除したいことが多いです。

function removeIf(array, predicate) {
  if (!Array.isArray(array)) {
    return [];
  }
  if (typeof predicate !== "function") {
    return array.slice();
  }

  return array.filter((item, index) => !predicate(item, index));
}
JavaScript

ここでは、「predicate が true を返した要素を削除する」というルールにしています。
filter で「!predicate(…)」を残すことで、「条件に合うものを除外」しているイメージです。

動作例:id が一致する要素を削除

const users = [
  { id: 1, name: "A" },
  { id: 2, name: "B" },
  { id: 3, name: "C" },
];

const result = removeIf(users, (u) => u.id === 2);

/*
[
  { id: 1, name: "A" },
  { id: 3, name: "C" },
]
*/
JavaScript

「id=2 のユーザーを削除する」という業務的な操作が、一行で書けます。


破壊的な splice とどう付き合うか

splice の問題点

JavaScript には splice という「その場で配列を書き換える削除」があります。

const arr = [10, 20, 30, 40];
arr.splice(1, 2); // インデックス1から2件削除

console.log(arr); // [10, 40]
JavaScript

便利ですが、元の配列が書き換わるのが大きなクセです。

業務コードでこれを多用すると、

どこかで配列が勝手に短くなっている。
別の処理が想定外の順番・要素数で動き始める。

といったバグにつながりやすくなります。

ユーティリティで「非破壊」を標準にする

removeAt / removeValue / removeAll / removeIf のように、
「必ず新しい配列を返す」「元の配列は変えない」というスタイルをユーティリティで固定しておくと、

「配列がいつどこで変わったのか分からない」問題がかなり減ります。

どうしてもパフォーマンスなどの理由で破壊的にやりたいときだけ、
「ここは意図的に splice を使う」と明示して書く、という方針が安全です。


手を動かして感覚をつかむ

コンソールで、次のコードを実際に打ってみてください。

function removeAt(array, index) {
  if (!Array.isArray(array)) return [];
  const len = array.length;
  if (index < 0 || index >= len) return array.slice();
  const head = array.slice(0, index);
  const tail = array.slice(index + 1);
  return [...head, ...tail];
}

function removeValue(array, value) {
  if (!Array.isArray(array)) return [];
  const index = array.indexOf(value);
  if (index === -1) return array.slice();
  return removeAt(array, index);
}

function removeAll(array, value) {
  if (!Array.isArray(array)) return [];
  return array.filter((item) => item !== value);
}

function removeIf(array, predicate) {
  if (!Array.isArray(array)) return [];
  if (typeof predicate !== "function") return array.slice();
  return array.filter((item, index) => !predicate(item, index));
}

const arr = [10, 20, 30, 40, 20];

console.log(removeAt(arr, 2));              // [10, 20, 40, 20]
console.log(removeValue(arr, 20));          // [10, 30, 40, 20]
console.log(removeAll(arr, 20));            // [10, 30, 40]
console.log(removeIf(arr, (v) => v >= 30)); // [10, 20, 20]
console.log(arr);                           // [10, 20, 30, 40, 20]
JavaScript

「どの削除がどう効いているか」「元の配列が変わっていないこと」を、自分の目で確認してみてください。


まとめ:要素削除ユーティリティを“標準の削除手段”にする

業務コードでは、配列から要素を消す場面が本当に多いです。
そのたびに splicefilter を直書きするのではなく、

export function removeAt(...) { ... }
export function removeValue(...) { ... }
export function removeAll(...) { ... }
export function removeIf(...) { ... }
JavaScript

のようなユーティリティを用意して、「配列から要素を削除したいときは必ずこれを通す」と決めておくと、
削除ロジックが統一されて、バグも読みづらさも一気に減ります。

「何を基準に削除するか」と「元配列を壊すかどうか」を、
毎回意識的に選べるようになることが、配列操作を“業務レベル”に引き上げるポイントです。

タイトルとURLをコピーしました