JavaScript
メモ

【JavaScript】配列から重複を排除する【個人的メモ】

はじめに

配列を受けとり、重複を排除するコードをJavaScriptで実装したものです。
reduce()関数を使います。

補足

下記の、Reactのチュートリアルに関連して派生。
https://reactjs.org/docs/thinking-in-react.html

ProductTableコンポーネント内での、ProductCategoryRowとProductRowの出し分けの処理において、
入力がソート済みの配列であることを前提としていたので、
「ソート済みでない配列の場合はどうするべきか」と考えたのがきっかけです。

関数型での書き方に慣れていないため、復習を兼ねてメモ。

実装

データ構造

Input

入力データは以下のような構造となります。
サンプルではcategoryごとに値が並んでいますが、順不同のケースでも対応できるようにしたい、というのが意図です。

const products = 
[
  {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
  {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
  {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
  {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
  {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
  {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
];

Output

入力となる配列の各要素オブジェクトから"category"を取りだした後、重複を除去してこれを配列に入れて返却します。
下記のような結果を返す関数を実装します。

// コード
const result = extract_category(products);
console.log(result);

// 出力結果
["Electronics", "Sporting Goods"]

実装されたコード

function extract_category(items) {
  const categories = items
  .map((item) => {return item.category}) // 1. 各要素オブジェクトから、"category"のみを抽出
  .sort() // 2. "category"の値が格納された配列をソート
  .reduce((array, item) => { // 3. uniqueな値のみ抽出
    if (array.includes(item) === false){
      array.push(item);
    }

    return array;
  },[]);

  return categories;
};

処理の流れを整理すると下記のようになります。

  1. 各要素オブジェクトから、"category"のみを抽出
    map()関数を使うことで、要素オブジェクトから特定の項目のみを抽出することができました。
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map

  2. "category"の値が格納された配列をソート
    sort()関数を使い、値をソートします。
    stableではない(入力値が同値を持つ場合、入力と同じ順序にならない可能性がある)仕様ですが、今回のケースでは特に問題になりません。
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

  3. uniqueな値のみ抽出
    reduce()関数は、第1引数に処理を行う関数オブジェクト(ここではaccumulatorと呼びます)が、第2引数に初期値が渡されます。
    accumulatorは2つの引数をとります。
    第1引数には直前の処理で返却された値が、第2引数には処理対象の配列の値が渡されます。
     
    今回の処理では、まずreduce()関数の第2引数(初期値)として空の配列(返却値格納用)を渡します。
    accumulatorは、第2引数に渡された値を一つ一つ検査し、返却値格納用の配列に存在しなければこれに追加、存在すれば追加しないで次の値の検査に進みます。
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
     
    ちなみに配列に値が存在するかどうかの検査は、Array.prototype.includes()を使っています。
    一部のWebブラウザでは動かないと思います。
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes

実行環境

今回はCodepenを利用しました。思いついたらすぐに試せるのが良いですね。
https://codepen.io/