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

JavaScript JavaScript
スポンサーリンク

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

ここでの「空要素削除」は、配列の中から「いらない空っぽの値」を取り除いて、きれいな配列にする処理です。
英語だと compactclean などと呼ばれます。

業務では、例えばこんな場面でよく出てきます。
フォーム入力で「空の行」が混ざっているので、送信前に消したい。
CSV をパースしたら、nullundefined、空文字がたくさん入っていた。
API からのレスポンスに「値なし」の要素が混ざっていて、集計の邪魔になる。

こういうときに「空要素削除ユーティリティ」があると、毎回同じ条件でクリーンアップできて、バグも減ります。


まず決めるべきこと:「何を“空”とみなすか」

よくある「空」の候補

「空要素削除」で一番大事なのは、何を“空”とみなすかを決めることです。
よく候補に上がるのは次のような値です。

null
undefined
空文字 ""
空白だけの文字 " "
NaN
0(これは多くの場合「空」ではなく「有効な値」です)

ここを曖昧にしたまま書き始めると、「このケースでは消えるのに、あっちでは消えない」といった混乱が起きます。
なので、まずは「最小限の空」として nullundefined だけを消すところから始めるのがおすすめです。


基本形:null / undefined を消す空要素削除

一番シンプルな compact ユーティリティ

まずは、「nullundefined を削除する」だけのシンプルなユーティリティを書きます。

function compactNullable(array) {
  if (!Array.isArray(array)) {
    return [];
  }

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

ここでのポイントは、item != null という条件です。
!=(ゆるい等価)は、nullundefined の両方にマッチします。

item != null
item !== null && item !== undefined
と同じ意味です。

つまり、「nullundefined だけを消して、それ以外は全部残す」動きになります。

実際の動き

const data = [1, null, 2, undefined, 3, 0, "", false];

const cleaned = compactNullable(data);
// [1, 2, 3, 0, "", false]
JavaScript

0 や空文字 ""false は「有効な値」として残っています。
「とりあえず null/undefined だけ消したい」という場面では、この compactNullable で十分です。


もう一歩踏み込む:「空文字」や「空白だけ」も消したい

文字列入力を扱うときの「空」の扱い

フォームや CSV など、文字列入力を扱う場面では、
""(完全な空文字)や " "(空白だけの文字列)も「空」とみなしたいことが多いです。

その場合は、「空文字・空白だけの文字列も削除する」ユーティリティを用意します。

function isEmptyValue(value) {
  if (value == null) {
    return true;
  }

  if (typeof value === "string") {
    return value.trim().length === 0;
  }

  return false;
}

function compactEmpty(array) {
  if (!Array.isArray(array)) {
    return [];
  }

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

isEmptyValue が「空かどうか」を判定する関数です。
compactEmpty は、「空ではないものだけを残す」フィルタです。

ここでの重要ポイントは、trim() を使っていることです。
" " のような空白だけの文字列も、trim() すると "" になり、長さ 0 と判定できます。

実際の動き

const data = [1, null, 2, undefined, 3, 0, "", "   ", "A", false];

const cleaned = compactEmpty(data);
// [1, 2, 3, 0, "A", false]
JavaScript

null / undefined / "" / " " は削除され、
0"A"false は残っています。


条件をカスタマイズできる「汎用フィルタ」型ユーティリティ

「プロジェクトごとに“空”の定義が違う」問題

現実のプロジェクトでは、「この画面では 0 も空扱い」「この処理では 0 は有効」といった違いが出てきます。
そのたびに compactEmpty をコピーして条件を変えるのはつらいので、
「判定関数を渡せる汎用ユーティリティ」を用意しておくと便利です。

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

  if (typeof isEmpty !== "function") {
    return array.slice();
  }

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

isEmpty は、「その値が“空”かどうかを判定する関数」です。
true を返したものは削除され、false を返したものは残ります。

実際の使い方

例えば、「0 も空扱いにしたい」場合はこう書けます。

const data = [0, 1, 2, null, "", "A"];

const cleaned = compactBy(data, (value) => {
  if (value == null) return true;
  if (typeof value === "string" && value.trim().length === 0) return true;
  if (value === 0) return true;
  return false;
});
// [1, 2, "A"]
JavaScript

「空の定義」を関数として外に出しておくことで、
処理ごとに柔軟に変えられるようになります。


空要素削除を業務でどう使うか

例1:フォームの「空行」を送信前に削除する

ユーザーが「明細行を追加」できるフォームで、
空の行(何も入力されていない行)が混ざることはよくあります。

const rows = [
  { name: "A", qty: 1 },
  { name: "", qty: null },
  { name: "B", qty: 2 },
];
JavaScript

「名前も数量も空なら、その行は送信しない」というルールにしたい場合、
まず「行が空かどうか」を判定する関数を書きます。

function isEmptyRow(row) {
  if (!row || typeof row !== "object") return true;

  const nameEmpty = !row.name || String(row.name).trim().length === 0;
  const qtyEmpty = row.qty == null || row.qty === "";

  return nameEmpty && qtyEmpty;
}

const cleanedRows = rows.filter((row) => !isEmptyRow(row));
JavaScript

これは「配列の空要素削除」というより「オブジェクトの空判定」ですが、
考え方は同じで、「空の定義を関数に閉じ込めて、filter で削除する」スタイルです。

例2:CSV パース後の「空行」を削除する

CSV をパースすると、末尾に空行が入っていたり、
途中に「全部空の列」の行が紛れ込んでいたりします。

const rows = [
  ["A", "1"],
  ["", ""],
  ["B", "2"],
  [""],
];
JavaScript

「全てのセルが空なら、その行を削除する」ユーティリティはこう書けます。

function isEmptyCsvRow(row) {
  if (!Array.isArray(row) || row.length === 0) return true;

  return row.every((cell) => {
    if (cell == null) return true;
    if (typeof cell === "string" && cell.trim().length === 0) return true;
    return false;
  });
}

const cleanedRows = rows.filter((row) => !isEmptyCsvRow(row));
JavaScript

ここでも、「空の定義」を関数に閉じ込めて、filter で削除しています。


「空要素削除」ユーティリティ設計で意識してほしいポイント

1. 「空の定義」をはっきりさせる

一番大事なのは、「何を空とみなすか」を明文化することです。

null / undefined だけなのか。
空文字 "" も含めるのか。
空白だけの文字 " " も含めるのか。
0false はどう扱うのか。

これをユーティリティのレベルで決めておくと、
「この処理では消えるのに、あっちでは消えない」といった不思議な挙動を防げます。

2. 「破壊的」にしない(新しい配列を返す)

空要素削除は、基本的に「新しい配列を返す非破壊的な関数」にしておくのがおすすめです。

filter は元の配列を変更しないので、安全です。
元の配列を直接 splice でいじると、「どこで消えたのか」が追いにくくなります。

業務コードでは、「元データはそのまま」「クリーンな配列を別で持つ」というスタイルのほうが、
デバッグしやすく、バグも減ります。

3. 「null だけ」「文字列も含めて」「カスタム」の3段階を用意する

実装としては、次の 3 段階を用意しておくと使いやすいです。

compactNullablenull / undefined だけを削除する。
compactEmptynull / undefined / 空文字 / 空白だけの文字列を削除する。
compactBy … 呼び出し側が「空の定義」を関数で渡せる汎用版。

これを揃えておくと、「とりあえず null だけ消したい」「文字列もきれいにしたい」「この画面だけ特別なルールにしたい」といったニーズに、きれいに対応できます。


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

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

const data = [1, null, 2, undefined, 3, 0, "", "   ", "A", false];

compactNullable(data);
compactEmpty(data);

compactBy(data, (value) => {
  if (value == null) return true;
  if (typeof value === "string" && value.trim().length === 0) return true;
  if (value === 0) return true;
  return false;
});
JavaScript

「どの値が残って、どの値が消えるか」「空の定義を変えると結果がどう変わるか」を、自分の目で確認してみてください。

そのうえで、自分のプロジェクトに

export function compactNullable(...) { ... }
export function compactEmpty(...) { ... }
export function compactBy(...) { ... }
JavaScript

のような関数を置き、「配列をきれいにしたくなったら、必ずこの“空要素削除ユーティリティ”を通す」というルールを作ってみてください。
そうすると、「場当たり的な filter 条件の乱立」から、「意図と一貫性を持ったクレンジング処理」に一段ステップアップしていきます。

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