JavaScript Tips | 配列ユーティリティ:複数条件検索

JavaScript JavaScript
スポンサーリンク

何をしたいユーティリティか:「複数条件検索」

「複数条件検索」は、「この配列の中から、いくつかの条件をすべて満たす要素だけを探したい」ときに使うユーティリティです。
例えば、次のような“複数条件”が典型です。

  • 「ステータスが active で、かつ role が admin のユーザー」
  • 「在庫が 1 以上で、かつ価格が 1000 円以上 3000 円以下の商品」
  • 「エラーではなく、かつ警告フラグが立っているログ」

業務では「1つの条件だけ」より、「A かつ B」「A かつ B かつ C」のような複合条件のほうが圧倒的に多いです。
それを毎回ベタ書きせず、“複数条件をまとめて扱えるユーティリティ”にしておくと、コードがかなりスッキリします。


基本形:1件だけ見つける findByAll(AND 条件)

「すべての条件を満たす最初の1件」を返す

まずは、「複数条件をすべて満たす最初の1件」を探すユーティリティからいきます。

function findByAll(array, predicates) {
  if (!Array.isArray(array)) {
    return undefined;
  }
  if (!Array.isArray(predicates) || predicates.length === 0) {
    return undefined;
  }

  return array.find((item, index) =>
    predicates.every((p) => typeof p === "function" && p(item, index))
  );
}
JavaScript

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

  • predicates は「条件関数の配列」です(複数条件をここに詰める)
  • every を使って「すべての条件関数が true を返すか」をチェックしている
  • 1つでも false になったら、その要素は“条件を満たさない”
  • array.find(...) なので、「最初に条件を満たした1件」だけ返す(なければ undefined

つまり、「AND 条件(かつ)」での複数条件検索です。

例題:active かつ role=admin のユーザーを探す

const users = [
  { id: 1, name: "A", active: true,  role: "user" },
  { id: 2, name: "B", active: false, role: "admin" },
  { id: 3, name: "C", active: true,  role: "admin" },
];

const isActive = (u) => u.active === true;
const isAdmin  = (u) => u.role === "admin";

const user = findByAll(users, [isActive, isAdmin]);

console.log(user);
// { id: 3, name: "C", active: true, role: "admin" }
JavaScript

ここでは、

  • 条件1:active === true
  • 条件2:role === "admin"

この両方を満たす最初のユーザー(id=3)が返ってきます。


複数条件で「全部ほしい」パターン findAllByAll

「条件をすべて満たす要素を全部」取りたい

次は、「最初の1件」ではなく、「条件を満たすものを全部ほしい」パターンです。

function findAllByAll(array, predicates) {
  if (!Array.isArray(array)) {
    return [];
  }
  if (!Array.isArray(predicates) || predicates.length === 0) {
    return [];
  }

  return array.filter((item, index) =>
    predicates.every((p) => typeof p === "function" && p(item, index))
  );
}
JavaScript

find が「最初の1件」なのに対して、filter は「条件を満たすもの全部」です。
中身のロジックは findByAll とほぼ同じで、「every で AND 条件をまとめている」のがポイントです。

例題:在庫あり&価格 1000〜3000 円の商品を全部取得

const items = [
  { id: 1, stock: 0,  price: 500 },
  { id: 2, stock: 10, price: 1500 },
  { id: 3, stock: 5,  price: 4000 },
  { id: 4, stock: 3,  price: 2500 },
];

const hasStock   = (item) => item.stock > 0;
const priceInRange = (item) => item.price >= 1000 && item.price <= 3000;

const result = findAllByAll(items, [hasStock, priceInRange]);

console.log(result);
/*
[
  { id: 2, stock: 10, price: 1500 },
  { id: 4, stock: 3,  price: 2500 },
]
*/
JavaScript

「在庫あり」かつ「価格が範囲内」の商品だけが抽出されています。


AND だけじゃない:OR 条件の複数条件検索 findByAny / findAllByAny

「どれか1つでも条件を満たせばOK」(OR 条件)

ときには、「A か B のどちらかを満たしていればいい」という OR 条件も必要になります。
その場合は every ではなく some を使います。

function findByAny(array, predicates) {
  if (!Array.isArray(array)) {
    return undefined;
  }
  if (!Array.isArray(predicates) || predicates.length === 0) {
    return undefined;
  }

  return array.find((item, index) =>
    predicates.some((p) => typeof p === "function" && p(item, index))
  );
}

function findAllByAny(array, predicates) {
  if (!Array.isArray(array)) {
    return [];
  }
  if (!Array.isArray(predicates) || predicates.length === 0) {
    return [];
  }

  return array.filter((item, index) =>
    predicates.some((p) => typeof p === "function" && p(item, index))
  );
}
JavaScript

some は「1つでも true があれば true」を返します。
つまり、「複数条件のうち、どれか1つでも満たせばOK」という OR 条件になります。

例題:エラーか警告のログを全部取得

const logs = [
  { level: "info",    message: "OK" },
  { level: "warning", message: "Slow" },
  { level: "error",   message: "Failed" },
  { level: "debug",   message: "Detail" },
];

const isError   = (log) => log.level === "error";
const isWarning = (log) => log.level === "warning";

const result = findAllByAny(logs, [isError, isWarning]);

console.log(result);
/*
[
  { level: "warning", message: "Slow" },
  { level: "error",   message: "Failed" },
]
*/
JavaScript

「エラーまたは警告」のログだけを簡潔に取り出せています。


重要ポイント:条件を「関数の配列」にするメリット

条件を分解して再利用できる

isActiveisAdminhasStockpriceInRange のように、
条件を小さな関数として分けておくと、次のような良いことがあります。

  • 単体テストしやすい(条件だけテストできる)
  • 組み合わせを変えるだけで別の検索が書ける
  • 「この検索はどんな条件で絞っているか」が読みやすい

例えば、ユーザー検索で、

const isActive = (u) => u.active;
const isAdmin  = (u) => u.role === "admin";
const isEditor = (u) => u.role === "editor";
JavaScript

と分けておけば、

  • 「active な admin」 → [isActive, isAdmin]
  • 「active な editor」 → [isActive, isEditor]
  • 「admin または editor」 → OR 条件で [isAdmin, isEditor]

のように、条件の組み合わせだけで検索のバリエーションを増やせます。

AND / OR をユーティリティ名で明示する

findByAll(AND)と findByAny(OR)を分けておくと、
「この検索は“全部満たす必要がある”のか、“どれか1つでいい”のか」が関数名だけで分かります。

業務コードでは、「条件の意味が一目で分かる」ことがとても大事です。
every / some をそのまま書くより、ユーティリティ名で意図を表現するほうが読みやすくなります。


手を動かして複数条件検索の感覚をつかむ

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

function findByAll(array, predicates) {
  if (!Array.isArray(array)) return undefined;
  if (!Array.isArray(predicates) || predicates.length === 0) return undefined;
  return array.find((item, index) =>
    predicates.every((p) => typeof p === "function" && p(item, index))
  );
}

function findAllByAll(array, predicates) {
  if (!Array.isArray(array)) return [];
  if (!Array.isArray(predicates) || predicates.length === 0) return [];
  return array.filter((item, index) =>
    predicates.every((p) => typeof p === "function" && p(item, index))
  );
}

const users = [
  { id: 1, active: true,  role: "user" },
  { id: 2, active: false, role: "admin" },
  { id: 3, active: true,  role: "admin" },
];

const isActive = (u) => u.active;
const isAdmin  = (u) => u.role === "admin";

console.log(findByAll(users, [isActive, isAdmin]));
console.log(findAllByAll(users, [isActive, isAdmin]));
JavaScript

「どのユーザーがヒットするか」「条件を1つ増やしたらどう変わるか」を、自分の手で試してみてください。


まとめ:複数条件検索ユーティリティで“検索ロジック”を外出しする

業務コードでは、「複数条件での検索」が当たり前に出てきます。
そのたびに array.filter(...) の中で if (a && b && c) と書くのではなく、

  • 条件は小さな関数として分解する
  • AND / OR をユーティリティ(findByAll / findByAny など)に任せる
  • 検索ロジックを「配列ユーティリティ」として外出しする

こうしておくと、検索条件の変更・追加・テストがとても楽になります。

プロジェクトに次のような関数を置いておくイメージです。

export function findByAll(...) { ... }
export function findAllByAll(...) { ... }
export function findByAny(...) { ... }
export function findAllByAny(...) { ... }
JavaScript

「複数条件で探したくなったら、必ずこれを通す」と決めておくと、
検索ロジックが整理されて、コードの“業務レベル感”が一段上がります。

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