HOWTO · JavaScript

JavaScript で複数の条件をフィルタリングする

今日の記事では、JavaScript で複数の条件を使って配列をフィルタリングする方法を説明します。

このページの内容

JavaScript の filter() メソッドで、必要な条件をすべて満たす場合にだけ真を返す述語を使います。実行時に条件が渡される場合は、指定されたプロパティと値の組をそれぞれ比較します。条件があらかじめ決まっている場合は、比較式を && でつなぎます。どちらの場合も、filter() は条件に一致した要素を含む新しい配列を返します。

JavaScript で複数の条件をフィルタリングする

filter() メソッドは、配列内の値が割り当てられている各要素にコールバックを呼び出し、その戻り値が truthy(真とみなされる値)であれば要素を残します。要素自体を true または false に変更することはなく、元の配列も変更しません。コールバックには現在の要素、インデックス、配列が渡されますが、多くの述語で必要なのは要素だけです。返される配列は新しい配列ですが、含まれるオブジェクトは元の配列と同じオブジェクト参照です。

filter(callbackFn)

ここで callbackFn は述語です。要素を評価し、truthy または falsy(偽とみなされる値)を返します。一致する要素がなければ、空の配列が返されます。疎な配列では、値が割り当てられていないインデックスに対してコールバックは呼び出されないため、そのスロットは処理されません。コールバックの引数や動作の詳細は、MDN の filter() ドキュメントを参照してください。

従来の方法を使用する

条件の組がフォームなどのデータソースから渡される場合は、それらをオブジェクトに格納し、各エントリーを調べます。次の例では、指定された各キーがユーザー自身のプロパティとして存在し、その値が完全に一致することを条件にしています。指定した条件では、名前と住所の両方が一致するため Aleena が選ばれます。

const criteria = {
  address: 'India',
  name: 'Aleena'
};
const users = [
  {name: 'John Doe', email: 'johndoe@mail.com', age: 25, address: 'USA'},
  {name: 'Aleena', email: 'aleena@mail.com', age: 35, address: 'India'},
  {name: 'Mark Smith', email: 'marksmith@mail.com', age: 28, address: 'England'}
];

const filteredUsers = users.filter((user) => {
  return Object.entries(criteria).every(([key, value]) =>
    Object.prototype.hasOwnProperty.call(user, key) && user[key] === value
  );
});

console.log(filteredUsers);
[
  {
    name: 'Aleena',
    email: 'aleena@mail.com',
    age: 35,
    address: 'India'
  }
]

Object.entries(criteria) はプロパティと値の組を取り出し、every() はそのすべてが条件を満たすことを要求します。厳密等価演算子(===)では値と型の両方が一致する必要があります。プロパティがない場合も、指定された値とは一致しません。条件オブジェクトが空なら、各ユーザーについて every() は true を返すため、結果には全ユーザーが含まれます。この方法なら、フィールドごとに比較式を追加せず、任意のキーの組に対応できます。

自身のプロパティかどうかも確認するため、継承したプロパティが条件を満たすことはありません。ネストしたデータを扱う場合は、ネスト先の値を明示的に比較するか、そのフィールド用の述語を指定してください。この例で比較しているのはトップレベルの値です。

filter() メソッドを使用する

条件があらかじめ決まっている場合は、述語に比較式を直接書き、論理 AND 演算子(&&)でつなぎます。ユーザーを結果に残すには、それぞれの比較が true になる必要があります。次の例は単独で実行でき、動的な条件を使う例と同じユーザーが一致します。

const filter = {
  address: 'India',
  name: 'Aleena'
};
const users = [
  {name: 'John Doe', email: 'johndoe@mail.com', age: 25, address: 'USA'},
  {name: 'Aleena', email: 'aleena@mail.com', age: 35, address: 'India'},
  {name: 'Mark Smith', email: 'marksmith@mail.com', age: 28, address: 'England'}
];

const filteredUsers = users.filter(
  (user) => user.name === filter.name && user.address === filter.address
);

console.log(filteredUsers);
[
  {
    name: 'Aleena',
    email: 'aleena@mail.com',
    age: 35,
    address: 'India'
  }
]

フィールドと比較方法がプログラムのロジックで決まっている場合は、この直接的な書き方を使います。要求されるフィールドの組が変わる場合は、動的な方法が適しています。元のJSFiddle デモも参照できます。

述語では、要素を残す条件に集中します。残す要素には truthy な値を、除外する要素には falsy な値を返してください。&& は短絡評価されるため、先の比較が通った場合にだけ後続の比較が実行されます。意味が明確に保たれる範囲で、先に評価すると多くの要素を低コストで除外できる比較を前に置くとよいでしょう。