JavaScript 逆引き集 | filter で条件抽出

JavaScript JavaScript
スポンサーリンク

実務向け filter テンプレート

// 1) 基本(真偽で抽出)
const over10 = arr.filter(x => x > 10);

// 2) 型・null防御
const validUsers = (arr ?? []).filter(u =>
  u && typeof u.id === 'string' && typeof u.name === 'string'
);

// 3) 複数条件(AND / OR / NOT)
const premiumAdults = users.filter(u => u.age >= 18 && u.plan === 'premium');
const hasEmailOrPhone = users.filter(u => !!u.email || !!u.phone);
const excludeInactive = users.filter(u => !u.inactive);

// 4) 部分一致・大文字小文字無視
const q = 'tokyo';
const matched = items.filter(it =>
  (it.city ?? '').toLowerCase().includes(q.toLowerCase())
);

// 5) ユニーク抽出(Setを併用)
const uniqueIds = [...new Set(users.map(u => u.id))];

// 6) filter → map の王道連携
const adultIds = users.filter(u => u.age >= 18).map(u => u.id);

// 7) truthy だけ残す(空文字・null/undefined を除外)
const cleaned = values.filter(Boolean);
JavaScript

filter は「条件に合う要素だけを新配列として返す」非破壊的メソッドで、コールバック引数は element, index, array の3つ、疎配列の空スロットは呼ばれません。


性能とセキュリティのベストプラクティス

  • filter の目的を守る: 変換は map、集約は reduce、副作用は forEach。filter は「選別」に専念させると読みやすく保守しやすい。
  • 条件式は関数に分離: 複雑な条件は純粋関数に切り出し、テスト可能にする。再利用で重複を削減。
  • 巨大入力は段階化: 数十万件規模はチャンク処理・ストリーミング・仮想リストで分割。UI 側では v-virtual-list 等を検討。
  • 非同期誤用を避ける: filter のコールバックは同期で真偽を返す前提。非同期条件が必要なら先にメタ情報を取得してから同期 filter、または逐次 for…of+await。
  • 破壊的操作禁止: filter 中に元配列へ splice/push しない。選別結果は新配列で扱う。
  • 入力検証・エスケープ: 外部入力の配列はスキーマ検証。文字列を UI/DB/HTML に渡す場合はエスケープ・パラメータ化でインジェクション対策。
  • 疎配列の挙動: 空スロットはスキップされる点を理解して条件設計する。

React の実務テンプレート

// 検索+表示(安定 key)
function UserList({ users, query }) {
  const q = (query ?? '').trim().toLowerCase();

  const view = (users ?? [])
    .filter(u => u && typeof u.id === 'string' && typeof u.name === 'string')
    .filter(u => u.name.toLowerCase().includes(q)) // 条件抽出
    .map(u => ({ id: u.id, name: u.name.trim() })); // 整形は map

  return (
    <ul>
      {view.map(u => (
        <li key={u.id}>{u.name}</li>
      ))}
    </ul>
  );
}
JSX

React では「抽出は filter、整形は map、描画は宣言的に」という使い分けが基本です。for/forEach を JSX 内に直接書かず、前処理と表示を分離します Zenn Qiita


Vue の実務テンプレート

<template>
  <ul>
    <li v-for="u in filtered" :key="u.id">
      {{ u.name }} — {{ u.role ?? 'N/A' }}
    </li>
  </ul>
</template>

<script setup>
import { computed } from 'vue';

const props = defineProps({
  users: { type: Array, required: true },
  query: { type: String, default: '' }
});

const filtered = computed(() => {
  const q = (props.query ?? '').trim().toLowerCase();
  return (props.users ?? [])
    .filter(u => u && typeof u.id === 'string' && typeof u.name === 'string')
    .filter(u => u.name.toLowerCase().includes(q))
    .map(u => ({ id: u.id, name: u.name.trim(), role: u.role ?? 'N/A' }));
});
</script>
HTML

filter は「条件抽出」、map は「整形」という役割分担が分かりやすく、computed によるメモ化で不要再計算も抑制できます。


Node.js の実務テンプレート

// ログ行の抽出(レベルと期間でフィルタ)
export function selectLogs(lines, { levels = ['error', 'warn'], since }) {
  const allow = new Set(levels);
  const ts = since ? new Date(since).getTime() : 0;

  return (lines ?? [])
    .filter(l => l && typeof l.level === 'string' && typeof l.time === 'string')
    .filter(l => allow.has(l.level.toLowerCase()))
    .filter(l => new Date(l.time).getTime() >= ts);
}

// 抽出後に I/O(逐次/並列は要件で選択)
export async function saveFiltered(db, rows) {
  for (const r of rows) {
    await db.insert(r);
  }
}
JavaScript

filter は同期判定に向くため、I/O は抽出後に分離します。並列 I/O が必要なら別途並列数制御を導入します Zenn


ステップバイステップ具体実装(注文配列から条件抽出→表示→保存)

1. 型と検証

type Order = { id: string; item: string; qty: number; price: number; status?: 'open'|'closed'|'cancel' };

export function isOrder(x: any): x is Order {
  return x
    && typeof x.id === 'string'
    && typeof x.item === 'string'
    && Number.isFinite(x.qty)
    && Number.isFinite(x.price);
}
TypeScript

2. 条件抽出(filter)

export function selectExpensiveOpenOrders(orders, min = 20000) {
  return (Array.isArray(orders) ? orders : [])
    .filter(isOrder)
    .filter(o => o.status === 'open')
    .filter(o => Math.max(0, o.qty) * Math.max(0, o.price) >= min);
}
JavaScript

3. 整形(map)

export function toRows(orders) {
  return orders.map(o => {
    const qty = Math.max(0, o.qty);
    const price = Math.max(0, o.price);
    const total = qty * price;
    return {
      id: o.id,
      label: `${o.item} x${qty}`,
      total,
      expensive: total >= 20000,
    };
  });
}
JavaScript

4. React で表示

function OrderList({ orders }) {
  const selected = toRows(selectExpensiveOpenOrders(orders));
  return (
    <section>
      {selected.map(r => (
        <article key={r.id} className={r.expensive ? 'highlight' : ''}>
          <header>{r.label}</header>
          <div{r.total.toLocaleString()}</div>
        </article>
      ))}
    </section>
  );
}
JSX

5. Vue で表示

<template>
  <section>
    <article v-for="r in rows" :key="r.id" :class="{ highlight: r.expensive }">
      <header>{{ r.label }}</header>
      <div>¥{{ r.total.toLocaleString() }}</div>
    </article>
  </section>
</template>

<script setup>
import { computed } from 'vue';
import { selectExpensiveOpenOrders, toRows } from './orders.js';

const props = defineProps({ orders: { type: Array, required: true } });
const rows = computed(() => toRows(selectExpensiveOpenOrders(props.orders)));
</script>
HTML

6. Node.js で保存(逐次)

import { selectExpensiveOpenOrders, toRows } from './orders.js';

export async function saveFilteredOrders(db, orders) {
  const rows = toRows(selectExpensiveOpenOrders(orders));
  for (const r of rows) {
    await db.insert({ id: r.id, label: r.label, total: r.total });
  }
}
JavaScript

小さなライブラリ推奨とミニユーティリティ

  • 役割の徹底: filter で絞り、map で整形、必要なら reduce で集約。学習・現場ノウハウでもこの使い分けが基本として説明されています。
  • 部分導入: lodash-es のピンポイント import(例: import uniq from 'lodash-es/uniq')でバンドル軽量化。
  • 再利用ヘルパ: よく使う抽出や整形を小さな関数に抽出。
// compactFilter: truthy のみ残す(型ナローイング向け)
export function compactFilter(arr) {
  return (arr ?? []).filter(Boolean);
}

// byRange: 数値範囲抽出
export function byRange(arr, min, max) {
  return (arr ?? []).filter(n => Number.isFinite(n) && n >= min && n <= max);
}

// includeText: 部分一致抽出(大小無視)
export function includeText(arr, key, query) {
  const q = (query ?? '').toLowerCase();
  return (arr ?? []).filter(x => String(x?.[key] ?? '').toLowerCase().includes(q));
}
JavaScript

補足: filter は「条件に合致した要素だけの新配列」を返す非破壊的メソッド。map や forEach との使い分けは多数の解説で整理されており、filter→map の連携も定番です。

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