😗

[Javascript] フロントでよく使う配列操作

2023/04/14に公開

for文、forEachを乱用していた1年生

🆕 2024/07/13 連想配列での重複削除について追記しました。

Javascriptを使って開発をしていると、頻出する配列操作。
エンジニア1年生の時は、事あるごとにforEachかfor文を使っていたけれど
ネストが深くなったり冗長な処理になってしまう...

便利なメソッドがあると知っていても、
実際に開発をしているとどこで使えばいいのかわからなかったりしますよね。

私のようにエンジニア歴が浅い人の手助けになればいいなという思いも込めて
今回は便利な配列操作メソッドたちをシチュエーション別に備忘録的にまとめてみました

flatMap()

flatMapは配列の多重階層を解除し、別の配列を作成します。

flatMapの実態はmap関数とflat関数の2つの関数を掛け合わせた関数なので、
map()を実行した後にflat()を実行します。
flatは多次元の配列を1次元にする(フラットにする)ためのメソッドです。

そのため以下memberListのように配列の中に配列が入っていた場合に、
1次元にして新しい配列を作成することができます。

flatMap.js
 const memberList = [
  [
    { id: 1, userName: "nootbar", team: "cardinals" },
    { id: 2, userName: "kondo", team: "softbank" },
    { id: 3, userName: "ohtani", team: "angels" },
  ],
  [
    { id: 4, userName: "murakami", team: "yakult" },
    { id: 5, userName: "yoshida", team: "redsox" },
  ],
  [
    { id: 6, userName: "okamoto", team: "giants" },
    { id: 7, userName: "yamada", team: "yakult" },
    { id: 8, userName: "genda", team: "seibu" },
  ],
];

const flatMappedMember = memberList.flatMap((member) => member); 

console.log(flatMappedMember); 
// [ { "id": 1, "userName": "nootbar", "team": "cardinals" }, { "id": 2, "userName": "kondo", "team": "softbank" }, ..... { "id": 8, "userName": "genda", "team": "seibu" } ]

map()

mapは元の配列から新しい配列を作成します。
そのため配列の中からある要素だけ取り出して異なる配列を作成したい時などに使うことができます。

以下のサンプルでは
先ほどflatMapで作成したflatMappedMemberの中からteam名だけの配列を新たに作成しています。

map.js

[ 
  { id: 1, userName: "nootbar", team: "cardinals" },
  { id: 2, userName: "kondo", team: "softbank" },
  { id: 3, userName: "ohtani", team: "angels" },
  { id: 4, userName: "murakami", team: "yakult" },
  { id: 5, userName: "yoshida", team: "redsox" },
  { id: 6, userName: "okamoto", team: "giants" },
  { id: 7, userName: "yamada", team: "yakult" },
  { id: 8, userName: "genda", team: "seibu" },
];

const teamList = flatMapedMenber.map((member) => member.team);
console.log(teamList); // [ "cardinals", "softbank", "angels", "yakult", "redsox", "giants", "yakult", "seibu" ]

これをforEachで行うと、以下のように一度配列の受け皿を用意して
その中にpushしていく工程が必要になります。

forEach.js

const teamList = [];
flatMapedMenber.forEach((member) => {
  teamList.push(member.team)
});

一度だけならあまり行数は気にならないかもしれないですが、
同様の処理が複数ある場合コード量が多くなるのでmapで書いた方が簡潔ですね。

some()、every()

someは配列内の要素で1つでも条件に合致するものがあるかどうかを調べbooleanを返します。
everyは配列内の全ての要素が条件に合致するかどうかを調べbooleanを返します。

この2つの関数を実際のWeb開発などで使うとすると、
全件選択・全件選択解除のできるチェックボックスの挙動や
入力フォームで複数入力項目のうち1つでも未入力の項目があった場合に「送信」ボタンを非活性にするなどのUIの操作に応用できます。

以下のサンプルコードでは、teamListに格納されているリストの中で条件に合う要素があるか
チェックする処理を書いています。

some.js

// teamList 
// [ "cardinals", "softbank", "angels", "yakult", "redsox", "giants", "yakult", "seibu" ]

// team名に's'がつくチームが1つでもあるかチェック
const hasSTeamName = teamList.some((team) => team.includes("s"));
console.log(hasTeamName); // true

// 全てのteam名に's'が付くかチェック
const hasSAllTeamName = teamList.every((team) => team.includes("s"));
console.log(hasTeamName); // false

// team名が’nipponhamu'のチームが1つでもあるかチェック
const  isNipponHamu = teamList.some((team) => team == "nipponhamu");
console.log(isNipponHamu); // false


filter()

filterは配列の中からある条件に合致した要素だけを持つ新しい配列を作成します。

検索キーワードを元に絞り込みを行いたい検索機能の実装などを簡単に行うことができます。

下記のサンプルコードでは
flatMappedMember配列の中から、「teamプロパティの値がyakultのメンバーリスト」という条件を
指定してそれに合致した要素だけを持つ配列を作成しています。
条件に一致する要素が一つもない場合は空配列が出来上がります。

filter.js

// flatMappedMember
[ 
  { id: 1, userName: "nootbar", team: "cardinals" },
  { id: 2, userName: "kondo", team: "softbank" },
  { id: 3, userName: "ohtani", team: "angels" },
  { id: 4, userName: "murakami", team: "yakult" },
  { id: 5, userName: "yoshida", team: "redsox" },
  { id: 6, userName: "okamoto", team: "giants" },
  { id: 7, userName: "yamada", team: "yakult" },
  { id: 8, userName: "genda", team: "seibu" },
];

const filterdMember = flatMapedMenber.filter(
  (member) => member.team == "yakult"
);
console.log(filterdMember);
// [{ id: 4, userName: "murakami", team: "yakult" }, { id: 7, userName: "yamada", team: "yakult" } ]

// 条件に一致するものが一つもない場合は、空配列が作成される
const filterdMember2 = flatMapedMenber.filter(
  (member) => member.team == "hanshin"
);
console.log(filterdMember2); // []

find()

findは配列の中から条件に合致する要素を探して、最初に見つかった要素を取得します。
要素ではなくインデックスを取得したい場合はfindIndex()が使えます。

id○番の要素だけ取り出したいなど、特定の要素を1つだけ抽出したい時に便利です。

find.js

// flatMappedMember
[ 
  { id: 1, userName: "nootbar", team: "cardinals" },
  { id: 2, userName: "kondo", team: "softbank" },
  { id: 3, userName: "ohtani", team: "angels" },
  { id: 4, userName: "murakami", team: "yakult" },
  { id: 5, userName: "yoshida", team: "redsox" },
  { id: 6, userName: "okamoto", team: "giants" },
  { id: 7, userName: "yamada", team: "yakult" },
  { id: 8, userName: "genda", team: "seibu" },
];

  const member = flatMappedMember.find((member) => member.userName == 'ohtani');

  console.log(member); // { id: 3, userName: "ohtani", team: "angels" }

Mapを使って配列の重複を削除する

配列の中から重複したものを排除したい場合、調べるとfilterとfindIndexを使う方法が
多く出てきますが、今回はMapを使った方法をご紹介します。
扱うデータが少ない場合はfilterとfindIndexを使用したほうが早いのですが、
データ量が大きくなると圧倒的にMapが早いからです。

実装中に体感したのですが、こちらの記事に検証結果が詳しく書かれていました。

dupelicate.js

// id:1とid:4を重複させた配列
const members = [ 
  { id: 1, userName: "nootbar", team: "cardinals" },
  { id: 2, userName: "kondo", team: "softbank" },
  { id: 3, userName: "ohtani", team: "angels" },
  { id: 4, userName: "murakami", team: "yakult" },
  { id: 5, userName: "yoshida", team: "redsox" },
  { id: 6, userName: "okamoto", team: "giants" },
  { id: 7, userName: "yamada", team: "yakult" },
  { id: 8, userName: "genda", team: "seibu" },
  { id: 1, userName: "nootbar", team: "cardinals" },
  { id: 4, userName: "murakami", team: "yakult" },
];

const uniqueMembers = Array.from(
  new Map(members.map((member) => [member.id, member])).values()
);

Mapはkey-value型のオブジェクトで、任意の値をkeyとして使用することができます。
ここではmemberのidがkeyでmemberがvalueとなるようにMapを作成します。

values()valueだけを取り出したオブジェクトを返すので、Array.from()を使って配列にします。Mapでは同じkeyに違う値を設定できないので、Mapを作成する際に重複が削除されるという仕組みです。

Discussion