JavaScript Tips | 配列ユーティリティ:条件抽出

JavaScript JavaScript
スポンサーリンク

何をしたいユーティリティか:「条件抽出」

「条件抽出」は、配列の中から「ある条件に当てはまる要素だけ」を取り出す処理です。
JavaScript 標準の Array.prototype.filter を、業務で使いやすい形に“言語化”したものだと思ってください。

業務だと、例えばこういう場面で使います。
「有効なユーザーだけ」を一覧に出したい。
「ステータスが完了のものだけ」を集計したい。
「金額が 1 万円以上の明細だけ」を別の処理に回したい。

毎回 filter を直書きしても動きますが、「条件抽出ユーティリティ」としてまとめておくと、
「何を抽出しているコードなのか」が一気に読みやすくなります。


基本形:条件を関数で受け取る filterBy

「残したい条件」を関数にする

条件抽出の一番素直な形は、「残したいかどうかを判定する関数」を受け取るユーティリティです。

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

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

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

ここでの重要ポイントをかみ砕きます。

配列でなければ空配列を返す(安全側)。
predicate が関数でなければ、そのままコピーして返す(何もしない)。
filter の中で「残したいものだけ」を返す=predicate(...) が true のものだけ残す。

つまり、「predicate が true を返した要素だけを抽出する」ユーティリティです。

動作イメージ

例えば、「値が 0 より大きいものだけ抽出したい」場合。

const nums = [10, -5, 0, 20];

const positiveOnly = filterBy(nums, (n) => n > 0);
// [10, 20]
JavaScript

「残したい条件」を n > 0 として書き、それを filterBy に渡しています。
標準の filter とやっていることは同じですが、「条件抽出」という意図が関数名に出ているのがポイントです。


よくある業務パターン別の条件抽出

ステータスで抽出する

例えば、次のような配列があるとします。

const items = [
  { id: 1, status: "active" },
  { id: 2, status: "deleted" },
  { id: 3, status: "active" },
];
JavaScript

status: "active" のものだけ抽出したい」場合。

const activeItems = filterBy(items, (item) => item.status === "active");
/*
[
  { id: 1, status: "active" },
  { id: 3, status: "active" },
]
*/
JavaScript

ここでのポイントは、「残したい条件」を item.status === "active" として、
それを filterBy に渡していることです。

金額で抽出する

明細の配列から、「金額が 10,000 以上のものだけ」を抽出したいケース。

const lines = [
  { id: 1, amount: 5000 },
  { id: 2, amount: 15000 },
  { id: 3, amount: 8000 },
];

const largeLines = filterBy(lines, (line) => line.amount >= 10000);
/*
[
  { id: 2, amount: 15000 },
]
*/
JavaScript

「抽出条件」が業務仕様そのものなので、
ここをユーティリティに閉じ込めておくと、後から読み返したときに意図が分かりやすいです。


条件抽出を「名前付き関数」で表現する

条件に名前を付けると一気に読みやすくなる

抽出条件が複雑になってきたら、それを名前付き関数にしておくと、コードの意図が一気に読みやすくなります。

function isActive(item) {
  return item.status === "active";
}

function isLargeAmount(line) {
  return line.amount >= 10000;
}

const activeItems = filterBy(items, isActive);
const largeLines = filterBy(lines, isLargeAmount);
JavaScript

「この配列は“アクティブなものだけ”なんだな」「この配列は“大きな金額だけ”なんだな」と、
関数名だけで伝わります。

条件抽出は「業務ルールそのもの」なので、
ここに名前を付けておくことは、仕様書を書くのに近い意味を持ちます。


条件抽出と条件削除の関係

「残す」か「削る」かの違い

前にやった「条件削除」は、「削除したい条件」を書く関数でした。

const visibleItems = removeBy(items, (item) => item.status === "deleted");
JavaScript

今回の「条件抽出」は、「残したい条件」を書く関数です。

const activeItems = filterBy(items, (item) => item.status === "active");
JavaScript

どちらも内部的には filter を使っていますが、
「頭の中で何を考えているか」が違います。

削除したい条件が仕様としてはっきりしているなら removeBy
残したい条件で考えるほうが自然なら filterBy

この使い分けを意識すると、コードの意図がぐっと伝わりやすくなります。


インデックスや複数条件を使った抽出

インデックスを使う

filterBypredicate は、第 2 引数にインデックスも受け取れます。

const data = ["A", "B", "C", "D"];

const oddIndex = filterBy(data, (value, index) => index % 2 === 1);
// ["B", "D"]
JavaScript

「偶数番目だけ」「奇数番目だけ」といった抽出も、同じユーティリティで書けます。

複数条件を組み合わせる

例えば、「アクティブかつ金額が 10,000 以上」のものだけ抽出したい場合。

function isActive(item) {
  return item.status === "active";
}

function isLargeAmount(item) {
  return item.amount >= 10000;
}

function isActiveAndLarge(item) {
  return isActive(item) && isLargeAmount(item);
}

const filtered = filterBy(items, isActiveAndLarge);
JavaScript

条件を小さな関数に分けて、それを組み合わせることで、
「業務ルールの組み合わせ」がコードとして見えるようになります。


条件抽出ユーティリティで意識してほしいポイント

「残したい条件」を明文化する

条件抽出は、「何を残したいか」がすべてです。
ここを関数として明文化しておくと、仕様がコードにそのまま乗ります。

isActive
isCompleted
isValidAmount

こういう名前を付けておくと、「この配列は何を表しているのか」が一目で分かります。

非破壊的であること

filterByfilter を使っているので、元の配列は変更されません。
これは意図的です。

元の配列をいじらないことで、「どこで何が抽出されたのか」が追いやすくなります。
業務コードでは、「元データはそのまま」「抽出結果を別で持つ」というスタイルのほうが、デバッグしやすく、バグも減ります。

「生の filter」と「filterBy」を使い分ける

正直、filterBy は中身としては array.filter(predicate) と同じです。
それでもユーティリティにする価値があるのは、「名前で意図を伝えられるから」です。

「ここは単に配列を絞り込んでいるだけ」なら生の filter でもいい。
「ここは業務的な“条件抽出”をしている」なら filterBy のほうが読みやすい。

このくらいの温度感で使い分けると、コードが気持ちよく整理されていきます。


手を動かして確認してみる

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

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

const nums = [10, -5, 0, 20];
const positiveOnly = filterBy(nums, (n) => n > 0);

const items = [
  { id: 1, status: "active", amount: 5000 },
  { id: 2, status: "deleted", amount: 15000 },
  { id: 3, status: "active", amount: 20000 },
];

function isActive(item) {
  return item.status === "active";
}

function isLargeAmount(item) {
  return item.amount >= 10000;
}

const activeItems = filterBy(items, isActive);
const largeActiveItems = filterBy(items, (item) => isActive(item) && isLargeAmount(item));
JavaScript

「どの要素が抽出されて、どの要素が落ちるか」「条件を変えると結果がどう変わるか」を、自分の目で確かめてみてください。

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

export function filterBy(...) { ... }
JavaScript

を置き、「配列から“条件に合うものだけ”を取り出したくなったら、必ずこの“条件抽出ユーティリティ”を通す」と決めてみてください。
それだけで、バラバラに書かれた filter 条件が整理されて、業務ロジックの見通しがぐっと良くなります。

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