web-dev-qa-db-ja.com

ES6マップ/セットをマージする最も簡単な方法は?

ES6マップを(Object.assignのように)結合する簡単な方法はありますか?そして、私たちがそれを見ている間に、(Array.concatのような)ES6セットについてはどうですか?

117
jameslk

セットの場合:

var merged = new Set([...set1, ...set2, ...set3])

地図の場合:

var merged = new Map([...map1, ...map2, ...map3])

複数のマップが同じキーを持つ場合、マージされたマップの値はそのキーを持つ最後のマージマップの値になります。

191
Oriol

これがジェネレータを使った私の解決策です:

地図の場合:

let map1 = new Map(), map2 = new Map();

map1.set('a', 'foo');
map1.set('b', 'bar');
map2.set('b', 'baz');
map2.set('c', 'bazz');

let map3 = new Map(function*() { yield* map1; yield* map2; }());

console.log(Array.from(map3)); // Result: [ [ 'a', 'foo' ], [ 'b', 'baz' ], [ 'c', 'bazz' ] ]

セットの場合:

let set1 = new Set(['foo', 'bar']), set2 = new Set(['bar', 'baz']);

let set3 = new Set(function*() { yield* set1; yield* set2; }());

console.log(Array.from(set3)); // Result: [ 'foo', 'bar', 'baz' ]
35
jameslk

私が理解していない理由のために、あなたは直接組み込みの操作で1つのセットの内容を別のものに加えることができません。

別のSetオブジェクトを渡していることを.add()が検出してから、そのSetからすべての項目を取得するのは当然のことです(これは、私の 独自のSetオブジェクト - ES6 Setが存在する前です)。仕様)が動作します。しかし、彼らはそれをそのように実装しないことを選びました。

代わりに、単一の.forEach()行でそれを実行できます。

var s = new Set([1,2,3]);
var t = new Set([4,5,6]);

t.forEach(s.add, s);
console.log(s);   // 1,2,3,4,5,6

そして、Mapの場合、これを実行できます。

var s = new Map([["key1", 1], ["key2", 2]]);
var t = new Map([["key3", 3], ["key4", 4]]);

t.forEach(function(value, key) {
    s.set(key, value);
});
26
jfriend00

編集

私の最初の解決策を他の解決策と比較してベンチマークしたところ、非常に非効率的であることがわかりました。

ベンチマーク自体は非常に興味深いものです( link )これは3つの解決策を比較したものです(高いほど良い)。

  • 値を1つずつ追加する@ bfred.itのソリューション(14,955 op/sec)
  • 自己起動型ジェネレータを使用する@ jameslkのソリューション(5,089 op/sec)
  • 自分のもの、reduce&spreadを使う(3,434 op/sec)

ご覧のとおり、@ bfred.itのソリューションは間違いなく勝者です。

性能+不変性

それを念頭に置いて、これは元のセットを変更せず、引数として組み合わせるための可変数のイテラブルを除いて、わずかに修正されたバージョンです。

function union(...iterables) {
  const set = new Set();

  for (let iterable of iterables) {
    for (let item of iterable) {
      set.add(item);
    }
  }

  return set;
}

使用法:

const a = new Set([1, 2, 3]);
const b = new Set([1, 3, 5]);
const c = new Set([4, 5, 6]);

union(a,b,c) // {1, 2, 3, 4, 5, 6}

元の答え

reducespread演算子を使用して、別のアプローチを提案したいと思います。

実装

function union (sets) {
  return sets.reduce((combined, list) => {
    return new Set([...combined, ...list]);
  }, new Set());
}

使用法:

const a = new Set([1, 2, 3]);
const b = new Set([1, 3, 5]);
const c = new Set([4, 5, 6]);

union([a, b, c]) // {1, 2, 3, 4, 5, 6}

ヒント:

rest演算子を使用して、インターフェースを少し見やすくすることもできます。

function union (...sets) {
  return sets.reduce((combined, list) => {
    return new Set([...combined, ...list]);
  }, new Set());
}

これで、配列のセットを渡す代わりに、任意の数の引数のセットを渡すことができます。

union(a, b, c) // {1, 2, 3, 4, 5, 6}
15
Asaf Katz

承認された答えは素晴らしいですが、それは毎回新しいセットを作成します。

代わりに既存のオブジェクトをmutateしたい場合は、ヘルパー関数を使用してください。

セット

function concatSets(set, ...iterables) {
    for (const iterable of iterables) {
        for (const item of iterable) {
            set.add(item);
        }
    }
}

使用法:

const setA = new Set([1, 2, 3]);
const setB = new Set([4, 5, 6]);
const setC = new Set([7, 8, 9]);
concatSets(setA, setB, setC);
// setA will have items 1, 2, 3, 4, 5, 6, 7, 8, 9

地図

function concatMaps(map, ...iterables) {
    for (const iterable of iterables) {
        for (const item of iterable) {
            map.set(...item);
        }
    }
}

使用法:

const mapA = new Map().set('S', 1).set('P', 2);
const mapB = new Map().set('Q', 3).set('R', 4);
concatMaps(mapA, mapB);
// mapA will have items ['S', 1], ['P', 2], ['Q', 3], ['R', 4]
12
bfred.it

セットを配列Setsにマージするには、次のようにします。

var Sets = [set1, set2, set3];

var merged = new Set([].concat(...Sets.map(set => Array.from(set))));

少なくともBabelでは、等価であるはずの次のものが失敗するのは、私にとっては少し不思議なことです。

var merged = new Set([].concat(...Sets.map(Array.from)));
5
user663031

Asaf Katzの答えに基づいて、TypeScript版を次に示します。

export function union<T> (...iterables: Array<Set<T>>): Set<T> {
  const set = new Set<T>()
  iterables.forEach(iterable => {
    iterable.forEach(item => set.add(item))
  })
  return set
}
0
ndp

const mergedMaps = (...maps) => {
    const dataMap = new Map([])

    for (const map of maps) {
        for (const [key, value] of map) {
            dataMap.set(key, value)
        }
    }

    return dataMap
}

使用法

const map = mergedMaps(new Map([[1, false]]), new Map([['foo', 'bar']]), new Map([['lat', 1241.173512]]))
Array.from(map.keys()) // [1, 'foo', 'lat']
0
dimpiax

いいえ、これらには組み込みの操作はありませんが、自分で簡単に作成できます。

Map.prototype.assign = function(...maps) {
    for (const m of maps)
        for (const kv of m)
            this.add(...kv);
    return this;
};

Set.prototype.concat = function(...sets) {
    const c = this.constructor;
    let res = new (c[Symbol.species] || c)();
    for (const set of [this, ...sets])
        for (const v of set)
            res.add(v);
    return res;
};
0
Bergi

意味をなさない(配列または別のセットから)複数の要素を追加するときにnew Set(...anArrayOrSet)を呼び出す既存のセットに

これをreduce関数で使用しますが、これは単純にばかげています。 ...arrayスプレッド演算子を使用できる場合でも、プロセッサ、メモリ、時間のリソースを浪費するため、この場合は使用しないでください。

// Add any Map or Set to another
function addAll(target, source) {
  if (target instanceof Map) {
    Array.from(source.entries()).forEach(it => target.set(it[0], it[1]))
  } else if (target instanceof Set) {
    source.forEach(it => target.add(it))
  }
}

デモスニペット

// Add any Map or Set to another
function addAll(target, source) {
  if (target instanceof Map) {
    Array.from(source.entries()).forEach(it => target.set(it[0], it[1]))
  } else if (target instanceof Set) {
    source.forEach(it => target.add(it))
  }
}

const items1 = ['a', 'b', 'c']
const items2 = ['a', 'b', 'c', 'd']
const items3 = ['d', 'e']

let set

set = new Set(items1)
addAll(set, items2)
addAll(set, items3)
console.log('adding array to set', Array.from(set))

set = new Set(items1)
addAll(set, new Set(items2))
addAll(set, new Set(items3))
console.log('adding set to set', Array.from(set))

const map1 = [
  ['a', 1],
  ['b', 2],
  ['c', 3]
]
const map2 = [
  ['a', 1],
  ['b', 2],
  ['c', 3],
  ['d', 4]
]
const map3 = [
  ['d', 4],
  ['e', 5]
]

const map = new Map(map1)
addAll(map, new Map(map2))
addAll(map, new Map(map3))
console.log('adding map to map',
  'keys', Array.from(map.keys()),
  'values', Array.from(map.values()))
0
Steven Spungin