何をしたいユーティリティか:「複数条件検索」
「複数条件検索」は、「この配列の中から、いくつかの条件をすべて満たす要素だけを探したい」ときに使うユーティリティです。
例えば、次のような“複数条件”が典型です。
- 「ステータスが 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))
);
}
JavaScriptfind が「最初の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))
);
}
JavaScriptsome は「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「エラーまたは警告」のログだけを簡潔に取り出せています。
重要ポイント:条件を「関数の配列」にするメリット
条件を分解して再利用できる
isActive、isAdmin、hasStock、priceInRange のように、
条件を小さな関数として分けておくと、次のような良いことがあります。
- 単体テストしやすい(条件だけテストできる)
- 組み合わせを変えるだけで別の検索が書ける
- 「この検索はどんな条件で絞っているか」が読みやすい
例えば、ユーザー検索で、
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「複数条件で探したくなったら、必ずこれを通す」と決めておくと、
検索ロジックが整理されて、コードの“業務レベル感”が一段上がります。
