🤝

JavaScriptで配列内オブジェクトの値から重複と空の値がない一次元の配列を作る

2022/07/08に公開

実装することがあったのでメモです。

[
  {
    "id": 1,
    "category": [0, 10, 11, 13]
  },
  {
    "id": 2,
    "category": [12, null]
  },
  {
    "id": 3,
    "category": ["", 13]
  },
  {
    "id": 4,
    "category": ""
  },
]

上記のような配列からcategoryの値を取り出して、nullや空の値を削除した以下のように平坦な配列を作る。

[0, 10, 11, 12, 13]

map()categoryの値のみの配列を作る

まずmap()categoryの値のみの配列を作る。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map

const array = [
  {
    "id": 1,
    "category": [0, 10, 11, 13]
  },
  {
    "id": 2,
    "category": [12, null]
  },
  {
    "id": 3,
    "category": ["", 13]
  },
  {
    "id": 4,
    "category": ""
  },
]

const categories = array.map((item) => item.category)

console.log(categories) //[[0, 10, 11, 13], [12, null], ["", 13], ""]

flat()でネストした配列を平坦化

配列を平坦化するのに便利なflat()を使う。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/flat

const categories = [
  [0, 10, 11, 13],
  [12, null],
  ["", 13],
  ""
]

const flatCategories = categories.flat()

console.log(flatCategories) //[0, 10, 11, 13, 12, null, "", 13, ""]

filter()で空の値やnullを削除

数字だけであればfilter(Number.isFinite)で一気に解決できる。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

const flatCategories = [0, 10, 11, 13, 12, null, "", 13, ""]

const filterCategories = flatCategories.filter(Number.isFinite)

console.log(filterCategories) //[0, 10, 11, 13, 12, 13]

文字列など複合した配列の場合は条件を指定してフィルタリングする。

const flatCategories = [0, 10, 11, 13, 12, null, "", 13, "", "aaa", "bbb"]

const filterCategories = flatCategories.filter((item) => item !== "" && item !== undefined && item !== null)

console.log(filterCategories) //[0, 10, 11, 13, 12, 13, "aaa", "bbb"]

空の値やnull、undefinedに加え数値「0」が削除されても構わない場合はfilter(Boolean)で解決できる。

const flatCategories = [0, 10, 11, 13, 12, null, "", 13, "", "aaa", "bbb"]

const filterCategories = flatCategories.filter(Boolean)

console.log(filterCategories) //[10, 11, 13, 12, 13, "aaa", "bbb"]

sort()で数字を昇順に並び替える

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

const filterCategories = [0, 10, 11, 13, 12, 13]

const sortCategories = filterCategories.sort((a, b) => a - b)

console.log(sortCategories) //[0, 10, 11, 12, 13, 13]

Setで重複を削除

Setを使えば簡単に重複を削除できる。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Set

const sortCategories = [0, 10, 11, 12, 13, 13]

const newCategories = [...new Set(filterCategories)]

console.log(newCategories) //[0, 10, 11, 13, 12]

まとめて書いてみる

const array = [
  {
    "id": 1,
    "category": [0, 10, 11, 13]
  },
  {
    "id": 2,
    "category": [12, null]
  },
  {
    "id": 3,
    "category": ["", 13]
  },
  {
    "id": 4,
    "category": ""
  },
]

const categories = [...new Set(
  array
    .map((item) => item.category)
    .flat()
    .filter(Number.isFinite)
    .sort((a, b) => a - b)
)]

console.log(categories) //[0, 10, 11, 12, 13]

flatMap()メソッドを利用する

flatMap()というメソッドを知った。

これはES2019でflat()と共に追加されていたもので、配列をマッピングしたあとにフラット化するメソッド。map()flat()を別々にコールするよりわずかに効率的とのこと。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap

以下のように書き換えられる。

const array = [...]

const categories = [...new Set(
  array
    .flatMap((item) => item.category)
    .filter(Number.isFinite)
    .sort((a, b) => a - b)
)]

console.log(categories) //[0, 10, 11, 12, 13]

Setで重複を削除してからsort()で並び替える

Setで重複を削除してからsort()で並び替えた方がソートする要素が減る。

ChatGPTからパフォーマンスが向上する可能性があるとアドバイスを受けたので、以下のように書き換える。

const array = [...]

const categories = [...new Set(
  array
    .flatMap((item) => item.category)
    .filter(Number.isFinite)
)].sort((a, b) => a - b)

console.log(categories) //[0, 10, 11, 12, 13]

以上です。大変勉強になりました。

GitHubで編集を提案

Discussion

ログインするとコメントできます