🦔

javascriptで和集合、積集合、差集合、排他的論理和を取得する際のスニペット

2021/06/07に公開

はじめに

javascriptで和集合、積集合、差集合、排他的論理和を取得する際のスニペットです。

和集合(Union)

const A = [1, 2, 4, 5, 7];
const B = [2, 3, 5, 6, 8];
// -> [1, 2, 3, 4, 5, 6, 7, 8]

// setを使う
[...new Set([...A, ...B])]

// reduceを使う
[...A, ...B].reduce((cur, acc) => [...cur, ...(cur.includes(acc) ? [] : [acc])], [] as number[]

// lodashのunionを使う
_.union(A, B)

配列の要素がオブジェクトの場合

const A = [
  { id: 1, x: 1 },
  { id: 2, x: 1 },
  { id: 4, x: 1 },
  { id: 5, x: 1 },
  { id: 7, x: 1 },
];
const B = [
  { id: 2, x: 1 },
  { id: 3, x: 1 },
  { id: 5, x: 1 },
  { id: 6, x: 1 },
  { id: 8, x: 1 },
];
// -> idが同じものは同値とする
// [{ id: 1, x: 1 },
//  { id: 2, x: 1 },
//  { id: 3, x: 1 },
//  { id: 4, x: 1 },
//  { id: 5, x: 1 },
//  { id: 6, x: 1 },
//  { id: 7, x: 1 },
//  { id: 8, x: 1 }];

// reduce使う
[...A, ...B].reduce((acc, cur) => [...acc, ...(acc.some((item) => item.id === cur.id) ? [] : [cur])],[] as { id: number; x: number }[])

// lodashのunionByを使う
_.unionBy(A, B, 'id')

// lodashのunionWithを使う
_.unionWith(A, B, (a, b) => a.id === b.id)

積集合(Intersection)

const A = [1, 2, 4, 5, 7];
const B = [2, 3, 5, 6, 8];
// -> [2, 5]

// filterを使う
A.filter((valA) => B.includes(valA))

// lodashのintersectionを使う
_.intersection(A, B)

配列の要素がオブジェクトの場合

const A = [
  { id: 1, x: 1 },
  { id: 2, x: 1 },
  { id: 4, x: 1 },
  { id: 5, x: 1 },
  { id: 7, x: 1 },
];
const B = [
  { id: 2, x: 1 },
  { id: 3, x: 1 },
  { id: 5, x: 1 },
  { id: 6, x: 1 },
  { id: 8, x: 1 },
];
// -> idが同じものは同値とする
// [{ id: 2, x: 1 },
// { id: 5, x: 1 },];

// filterを使う
A.filter((valA) => B.some((valB) => valB.id === valA.id))

// lodashのintersectionByを使う
_.intersectionBy(A, B, 'id')

// lodashのintersectionWithを使う
_.intersectionWith(A, B, (a, b) => a.id === b.id)

差集合(difference)

const A = [1, 2, 4, 5, 7];
const B = [2, 3, 5, 6, 8];
// -> A - Bは[1, 4, 7]

// filterを使う
A.filter((val) => !B.includes(val))

// reduceを使う
 A.reduce((acc, cur) => [...acc, ...(B.includes(cur) ? [] : [cur])], [] as number[])

// lodashのdifferenceを使う
_.difference(A, B)

配列の要素がオブジェクトの場合

const A = [
  { id: 1, x: 1 },
  { id: 2, x: 1 },
  { id: 4, x: 1 },
  { id: 5, x: 1 },
  { id: 7, x: 1 },
];
const B = [
  { id: 2, x: 1 },
  { id: 3, x: 1 },
  { id: 5, x: 1 },
  { id: 6, x: 1 },
  { id: 8, x: 1 },
];
// -> idが同じものは同値とする
// [{ id: 1, x: 1 },
// { id: 4, x: 1 },
// { id: 7, x: 1 }]

// filterを使う
A.filter((valA) => !B.some((valB) => valA.id === valB.id))

// lodashのdifferenceByを使う
_.differenceBy(A, B, 'id')

// lodashのdifferenceWithを使う
_.differenceWith(A, B, (a, b) => a.id === b.id)

排他的論理和(xor)

const A = [1, 2, 4, 5, 7];
const B = [2, 3, 5, 6, 8];
// -> [1, 3, 4, 6, 7, 8];

// filterを使う
[...A, ...B].filter((val, _, arr) => arr.filter((v) => v === val).length === 1)

// reduceを使う
[...A, ...B].reduce((acc, cur, _, arr) => [...acc, ...(arr.filter((val) => val === cur).length === 1 ? [cur] : [])], [] as number[])

// lodashのxorを使う
_.xor(A, B)

配列の要素がオブジェクトの場合

const A = [
  { id: 1, x: 1 },
  { id: 2, x: 1 },
  { id: 4, x: 1 },
  { id: 5, x: 1 },
  { id: 7, x: 1 },
];
const B = [
  { id: 2, x: 1 },
  { id: 3, x: 1 },
  { id: 5, x: 1 },
  { id: 6, x: 1 },
  { id: 8, x: 1 },
];
// -> idが同じものは同値とする
// [{ id: 1, x: 1 },
//  { id: 3, x: 1 },
//  { id: 4, x: 1 },
//  { id: 6, x: 1 },
//  { id: 7, x: 1 },
//  { id: 8, x: 1 }]

// filterを使う
[...A, ...B].filter((val, _, arr) => arr.filter((v) => v.id === val.id).length === 1)

// lodashのxorByを使う
_.xorBy(A, B, 'id')

// lodashのxorWithを使う
_.xorWith(A, B, (a, b) => a.id === b.id)

参照

https://qiita.com/waterada/items/6d92175c0cebecd410c6

Setでの集合論のメソッドは現在stage2のようです
https://github.com/tc39/proposal-set-methods

Discussion