読み込み中...

LodashのpickByを使ってデータを効率的に整形する方法6選

JavaScriptのLodashライブラリのpickByメソッドを使ったデータ整形 JS
この記事は約19分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

●Lodashとは?

JavaScriptの開発において、配列やオブジェクトの操作は日常茶飯事ですよね。

でも、ネイティブのJavaScriptだけでは、少し複雑になってしまうことがあります。

そんな時に役立つのが、Lodashというユーティリティライブラリです。

○Lodashの特徴

Lodashは、配列やオブジェクトをもっと簡潔に、わかりやすく操作するためのメソッドを豊富に提供してくれています。

例えば、配列から特定の条件に合致する要素だけを抽出したり、オブジェクトのプロパティを絞り込んだりといったことが、ワンライナーで実現できちゃうんです。

こうしたLodashの特徴は、コードの可読性を高めてくれるだけでなく、開発の生産性向上にも一役買ってくれます。

複雑な処理を実装する際も、Lodashのメソッドを組み合わせれば、スッキリとしたコードで表現できるでしょう。

○Lodashのインストール方法

Lodashを使うためには、まずnpmでインストールする必要があります。

プロジェクトのルートディレクトリで、次のコマンドを実行しましょう。

npm install lodash

これだけで、プロジェクト内でLodashが利用可能になります。

あとは、必要なファイルでLodashをインポートすれば、その強力なメソッドの数々を活用できるというわけです。

import _ from 'lodash';

さて、Lodashにはたくさんの便利なメソッドがありますが、今回は特にpickByメソッドに注目していきたいと思います。

pickByを使いこなせば、オブジェクトのプロパティを条件に応じて抽出する処理が、驚くほどシンプルに書けちゃうんですよ。

●pickByメソッドの概要

Lodashの中でも特に便利なメソッドの1つが、pickByです。

オブジェクトから条件に合致するプロパティだけを抽出してくれる強力なメソッドですね。

プロジェクトを進めていると、APIレスポンスから必要なデータだけを取り出したり、ユーザー入力のバリデーションをしたりと、オブジェクトを加工する場面が多々あります。

そんな時、pickByを使えば、条件に基づいてプロパティを選択できるので、データの整形がグッと楽になります。

○pickByの基本的な使い方

pickByの使い方は至ってシンプルです。

第1引数にオブジェクト、第2引数に条件を表す関数を渡すだけ。

戻り値として、条件を満たすプロパティだけが残った新しいオブジェクトが返ってきます。

const _ = require('lodash');

const user = {
  id: 1,
  name: 'John Doe',
  age: 25,
  email: 'john@example.com',
  isAdmin: false
};

const result = _.pickBy(user, (value, key) => {
  return typeof value === 'string';
});

console.log(result);

実行結果

{
  name: 'John Doe',
  email: 'john@example.com'
}

ご覧の通り、プロパティの値が文字列型であるもののみが抽出されていますね。

pickByに渡したコールバック関数では、valueにプロパティの値、keyにプロパティ名が渡されるので、それを利用して柔軟な条件を指定できるんです。

○サンプルコード1:プロパティ値が特定の条件を満たすものだけを抽出

例えば、数値型のプロパティの中から、特定の値以上のものだけを抜き出すなんてこともできてしまいます。

const _ = require('lodash');

const scores = {
  math: 85,
  english: 92,
  science: 76,
  history: 68
};

const result = _.pickBy(scores, score => score >= 80);

console.log(result);

実行結果

{
  math: 85,
  english: 92
}

pickByを使えば、オブジェクトのフィルタリングがこんなにスマートに書けます。

コールバック関数の条件次第で、実に様々なケースに対応できる万能メソッドだと言えるでしょう。

●pickByを使ったデータ整形テクニック6選

さて、ここからはpickByを使った実践的なデータ整形テクニックを6つご紹介していきたいと思います。

実際のプロジェクトでも応用できるような、役に立つサンプルコードを交えながら解説していきますので、ぜひ参考にしてみてくださいね。

○サンプルコード2:真偽値を返す関数で抽出条件を指定

先ほどは単純な条件式をコールバック関数に渡しましたが、もっと複雑な条件を指定したい場合はどうすればいいでしょうか。

そんな時は、真偽値を返す関数を用意して、それをpickByに渡すのがおすすめです。

const _ = require('lodash');

const users = [
  { id: 1, name: 'Alice', age: 25, isAdmin: false },
  { id: 2, name: 'Bob', age: 32, isAdmin: true },
  { id: 3, name: 'Carol', age: 19, isAdmin: false }
];

function isAdult(user) {
  return user.age >= 20 && !user.isAdmin;
}

const result = users.map(user => _.pickBy(user, isAdult));

console.log(result);

実行結果

[
  { age: 25 },
  {},
  { age: 19 }
]

isAdult関数では、ユーザーの年齢が20歳以上かつ管理者でないかをチェックしています。

このように、抽出条件を関数として切り出すことで、コードの見通しが良くなり、再利用もしやすくなりますね。

○サンプルコード3:特定のプロパティ名を持つものだけを抽出

オブジェクトの配列から、特定のプロパティ名を持つオブジェクトだけを抜き出したいこともあるでしょう。

そんな時は、pickByの第2引数にプロパティ名の配列を渡してあげれば簡単に実現できます。

const _ = require('lodash');

const books = [
  { id: 1, title: 'Book A', author: 'John', price: 1500 },
  { id: 2, title: 'Book B', author: 'Alice', price: 2000 },
  { id: 3, title: 'Book C', author: 'Bob', publicationYear: 2019 },
];

const result = books.map(book => _.pickBy(book, (value, key) => ['title', 'author'].includes(key)));

console.log(result);

実行結果

[
  { title: 'Book A', author: 'John' },
  { title: 'Book B', author: 'Alice' },
  { title: 'Book C', author: 'Bob' }
]

これで、titleとauthorプロパティだけが残ったオブジェクトの配列が得られました。

プロパティ名のホワイトリストを使って抽出する場合に便利ですね。

○サンプルコード4:複数の条件を組み合わせて抽出

複数の条件を組み合わせて、オブジェクトから抽出したいケースもあります。

pickByのコールバック関数内で、論理演算子を使えば、ANDやORの条件を表現できますよ。

const _ = require('lodash');

const products = [
  { id: 1, name: 'A', type: 'book', price: 1000, stock: 50 },
  { id: 2, name: 'B', type: 'game', price: 5000, stock: 20 },
  { id: 3, name: 'C', type: 'book', price: 1500, stock: 0 },
  { id: 4, name: 'D', type: 'game', price: 3000, stock: 30 },
];

const result = _.pickBy(products, product => 
  product.type === 'game' && product.price >= 4000 || product.stock > 0
);

console.log(result);

実行結果

[
  { id: 1, name: 'A', type: 'book', price: 1000, stock: 50 },
  { id: 2, name: 'B', type: 'game', price: 5000, stock: 20 },
  { id: 4, name: 'D', type: 'game', price: 3000, stock: 30 }  
]

商品の種類がゲームで価格が4000円以上、または在庫が0より大きいものだけを抽出しています。

論理演算子を使いこなせば、こんなふうに複雑な条件も表せるんです。

○サンプルコード5:ネストされたオブジェクトから抽出

オブジェクトがネストしている場合でも、pickByを使えば必要なプロパティだけを抜き出せます。

ネストされたオブジェクトを再帰的に処理することで、深い階層のプロパティにもアクセスできるようになりますよ。

const _ = require('lodash');

const data = {
  id: 1,
  user: {
    name: 'Alice',
    age: 25,
    contact: {
      email: 'alice@example.com',
      phone: '123-456-7890'
    }
  },
  posts: [
    { id: 1, title: 'Post A', body: 'This is post A.' },
    { id: 2, title: 'Post B', body: 'This is post B.' }
  ]
};

function customizer(value, key) {
  if (_.isObject(value)) {
    return _.pickBy(value, customizer);
  }
  return ['name', 'email'].includes(key);
}

const result = _.pickBy(data, customizer);

console.log(result);

実行結果

{
  user: {
    name: 'Alice',
    contact: {
      email: 'alice@example.com'
    }
  }
}

customizer関数内で、値がオブジェクトだった場合は再帰的にpickByを呼び出しています。

これにより、ネストされたオブジェクトの中からも、nameとemailのプロパティだけを抽出することができました。

○サンプルコード6:抽出結果をさらに加工

pickByで抽出したオブジェクトをそのまま使うだけでなく、さらに加工を加えたい場合もあるでしょう。

その場合は、pickByの結果をmapやforEachなどの配列メソッドで処理すると良いですよ。

const _ = require('lodash');

const users = [
  { id: 1, name: 'Alice', age: 25, email: 'alice@example.com' },
  { id: 2, name: 'Bob', age: 32, email: 'bob@example.com' },
  { id: 3, name: 'Carol', age: 19, email: 'carol@example.com' }
];

const result = _(users)
  .map(user => _.pickBy(user, (value, key) => ['name', 'email'].includes(key)))
  .map(user => ({ ...user, email: user.email.toUpperCase() }))
  .value();

console.log(result);  

実行結果

[
  { name: 'Alice', email: 'ALICE@EXAMPLE.COM' },
  { name: 'Bob', email: 'BOB@EXAMPLE.COM' },
  { name: 'Carol', email: 'CAROL@EXAMPLE.COM' }
]

ここでは、pickByでnameとemailだけを抽出した後、mapでemailを大文字に変換しています。

Lodashのチェーンメソッドを使えば、このように抽出と加工を一連の流れで書くことができますね。

●pickByを使う際の注意点

pickByは本当に便利なメソッドですが、使い方を間違えると、かえって悪影響を及ぼしてしまうこともあります。

ここでは、pickByを使う際に気をつけるべき点を3つご紹介しますね。

○パフォーマンスへの影響

まず注意したいのが、パフォーマンスへの影響です。

pickByは、オブジェクトのプロパティを1つ1つチェックしていくので、大きなオブジェクトを処理する場合は、少し時間がかかってしまうんですよ。

特に、pickByをループの中で使うと、パフォーマンスが大きく低下する可能性があります。

例えば、こんなコードは避けた方が良いでしょう。

const _ = require('lodash');

const bigData = [
  { id: 1, name: 'John', age: 25, email: 'john@example.com', ... },
  { id: 2, name: 'Alice', age: 32, email: 'alice@example.com', ... },
  ...
];

function extractData(data) {
  return data.map(item => _.pickBy(item, (value, key) => ['id', 'name'].includes(key)));
}

for (let i = 0; i < 100; i++) {
  const result = extractData(bigData);
  console.log(result);
}

こんな風に、大量のデータをループで処理する際にpickByを使うと、パフォーマンスが大きく低下してしまいます。

代わりに、mapの中でオブジェクトを直接作成するようにすれば、パフォーマンスを改善できますよ。

function extractData(data) {
  return data.map(({ id, name }) => ({ id, name }));
}

○可読性の保持

pickByを使えば、コードがスッキリして読みやすくなる反面、使いすぎると、かえって可読性が下がってしまうこともあります。

例えば、こんなコードは、ちょっと読みづらいですよね。

const user = {
  id: 1,
  name: 'John',
  age: 25,
  email: 'john@example.com',
  address: {
    city: 'New York',
    country: 'USA'
  }
};

const result = _.pickBy(user, (value, key) => 
  typeof value === 'string' || 
  typeof value === 'number' && key !== 'age' ||
  _.isObject(value) && key === 'address'
);

console.log(result);

実行結果

{
  name: 'John',
  email: 'john@example.com',
  address: { city: 'New York', country: 'USA' }
}

pickByの条件が複雑すぎると、何をしているのかわかりづらくなってしまいます。

こういう場合は、条件を変数や関数に切り出すと良いでしょう。

const isString = value => typeof value === 'string';
const isNumber = value => typeof value === 'number';
const isAddress = (value, key) => _.isObject(value) && key === 'address';

const result = _.pickBy(user, (value, key) =>
  isString(value) || isNumber(value) && key !== 'age' || isAddress(value, key)
);

○TypeScriptとの併用

JavaScriptの型付けを強化するTypeScriptと一緒にLodashを使う場合は、型定義ファイルをインストールしておくと良いでしょう。

npm install --save-dev @types/lodash

ただ、pickByで抽出したオブジェクトの型を明示的に指定するのは、ちょっと面倒かもしれません。

pickByは、元のオブジェクトの型から、特定のプロパティを取り除いた型を返すので、毎回正確に型を指定するのは大変ですからね。

interface User {
  id: number;
  name: string;
  age: number;
  email: string;
}

const user: User = {
  id: 1,
  name: 'John',
  age: 25,
  email: 'john@example.com'
};

const result = _.pickBy(user, (value, key) => ['id', 'name'].includes(key));
// resultの型は { id: number; name: string; } | { [key: string]: any } になる

こんな場合は、型アサーションを使って、resultの型を明示的に指定してあげると良いですよ。

const result = _.pickBy(user, (value, key) => ['id', 'name'].includes(key)) as Pick<User, 'id' | 'name'>;

pickByは本当に便利なメソッドですが、使い方を間違えると、パフォーマンスの低下や可読性の低下を招く恐れがあります。

何事もほどほどが大切ですね。

pickByの特性をきちんと理解した上で、適材適所で使っていきましょう!

●pickBy以外の関連メソッド

さて、ここまではずっとpickByメソッドについて見てきましたが、実はLodashには、pickBy以外にも、オブジェクトから特定のプロパティを抽出するためのメソッドがあるんです。

ここでは、そんなpickByの仲間たちを2つご紹介しますね。

○omitBy

omitByは、pickByの反対のメソッドだと思ってください。

pickByが条件に合致するプロパティを抽出するのに対し、omitByは条件に合致するプロパティを除外するんです。

使い方はpickByとほとんど同じですよ。

第1引数にオブジェクト、第2引数に条件を表す関数を渡します。

const _ = require('lodash');

const user = {
  id: 1,
  name: 'John',
  age: 25,
  email: 'john@example.com',
  isAdmin: false
};

const result = _.omitBy(user, (value, key) => typeof value === 'boolean');

console.log(result);

実行結果

{ id: 1, name: 'John', age: 25, email: 'john@example.com' }

このように、omitByを使えば、条件に合致するプロパティを簡単に除外できるんです。

今回の例では、真偽値型のプロパティを除外しています。

omitByは、オブジェクトから不要なプロパティを取り除くのに便利ですね。

APIレスポンスから使わないデータを削ったり、フォームの入力値からバリデーション用のフラグを除外したりと、様々な場面で活躍してくれますよ。

○pickとomitの違い

実は、pickByとomitByには、もっとシンプルなバージョンのメソッドがあります。

それが、pickとomitです。

pickとomitは、pickByとomitByの第2引数の関数を省略したようなメソッドだと思ってください。

第2引数には、抽出したいプロパティ名や除外したいプロパティ名の配列を渡します。

const _ = require('lodash');

const user = {
  id: 1,
  name: 'John',
  age: 25,
  email: 'john@example.com',
  isAdmin: false
};

const picked = _.pick(user, ['id', 'name']);
console.log(picked);

const omitted = _.omit(user, ['age', 'isAdmin']);
console.log(omitted);

実行結果

{ id: 1, name: 'John' }
{ id: 1, name: 'John', email: 'john@example.com' }

pickは、指定したプロパティ名の配列に含まれるプロパティだけを抽出します。

一方、omitは、指定したプロパティ名の配列に含まれるプロパティを除外します。

プロパティ名が静的に決まっている場合は、pickByやomitByよりもpickやomitの方がシンプルに書けて良いかもしれません。

でも、動的に条件を決めたい場合は、pickByやomitByの出番ですね。

まとめ

JavaScriptのユーティリティライブラリLodashのpickByメソッドについて、たっぷりとお話ししてきましたが、いかがでしたでしょうか。

pickByを使えば、オブジェクトから条件に合致するプロパティだけを抽出できるので、データの整形がぐっと楽になりますよね。

サンプルコードで見てきたように、pickByのコールバック関数では、プロパティの値だけでなく、キーも使って柔軟な条件を指定できます。

これで、様々なケースに対応できる万能のメソッドに早変わりです。