ES6 মানচিত্র / সেটগুলিকে মার্জ করার সহজ উপায়?


170

ES6 মানচিত্র একসাথে একত্রিত করার জন্য কি কোনও সহজ উপায় আছে (যেমন Object.assign)? এবং যখন আমরা এটি করছি, ES6 সেটগুলি (যেমন Array.concat) সম্পর্কে কী ?


4
এই ব্লগ পোস্ট কিছু অন্তর্দৃষ্টি আছে। 2ality.com/2015/01/es6-set-operations.html
লেমিএক্সস্টার

মানচিত্রের জন্য আফাইক আপনাকে ব্যবহার করতে হবে for..ofকারণ keyযে কোনও ধরণের হতে পারে
পল এস

উত্তর:


265

সেট জন্য:

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

মানচিত্রের জন্য:

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

মনে রাখবেন যে একাধিক মানচিত্রে একই কী থাকলে, একত্রিত মানচিত্রের মানটি সেই কীটির সাথে সর্বশেষ মার্জিং মানচিত্রের মান হবে।


4
নথিপত্র উপর Map: "রচয়িতা: new Map([iterable])", " iterableএকটি অ্যারের বা অন্যান্য iterable বস্তুর যার উপাদান কী-মান জোড়া (2- উপাদান অ্যারেগুলির) হয়। প্রতিটি মান-মান জুড়ি নতুন মানচিত্রে যুক্ত করা হয়। - ঠিক রেফারেন্স হিসাবে।
ব্যবহারকারী4642212

34
বৃহত্তর সেটগুলির জন্য, কেবলমাত্র সতর্ক করে দেওয়া হবে যে এটি দুটি সেটগুলির ইউনিট যুক্ত অস্থায়ী অ্যারে তৈরি করতে একবার উভয় সেটের সামগ্রিকে পুনরাবৃত্তি করে, তারপরে সেই অস্থায়ী অ্যারে সেট কনস্ট্রাক্টরে পাস করে যেখানে নতুন সেট তৈরি করতে আবার পুনরাবৃত্তি হয় ।
jender00

2
@ jender00: আরও ভাল পদ্ধতির জন্য নীচে জেমসেলকের জবাবটি দেখুন
বার্গি

2
@ টোরাজাবুরো: যেমন জেন্ডার00 বলেছেন, ওরিওলস সমাধান অযৌক্তিক মধ্যবর্তী অ্যারে তৈরি করে। কনট্রাক্টরটিতে একটি ইটারেটর পাস করা Mapতাদের মেমরির খরচ এড়ানো যায়।
বার্গি

2
আমি অভিযুক্ত যে ES6 সেট / মানচিত্র দক্ষ মার্জ পদ্ধতি সরবরাহ করে না।
অ্যান্ডি

47

জেনারেটর ব্যবহার করে আমার সমাধানটি এখানে দেওয়া হয়েছে:

মানচিত্রের জন্য:

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
(আইআইজিএফই = তাত্ক্ষণিকভাবে আহ্বান করা জেনারেটরের ফাংশন এক্সপ্রেশন)
ওরিওল

3
চমৎকার এছাড়াও m2.forEach((k,v)=>m1.set(k,v))যদি আপনি চান সহজ ব্রাউজার সমর্থনের
caub

9
@ কৌব সুন্দর সমাধান তবে মনে আছে যে forEach এর প্রথম প্যারামিটারটি মান তাই আপনার ফাংশনটি m2.forEach ((v, k) => m1.set (কে, ভি)) হওয়া উচিত;
ডেভিড নোরিয়া

44

যে কারণে আমি বুঝতে পারি না, আপনি অন্তর্নির্মিত অপারেশন দিয়ে একটি সেট এর সামগ্রী সরাসরি অন্য সেটটিতে যুক্ত করতে পারবেন না। ইউনিয়ন, ছেদ করা, মার্জ করা ইত্যাদির মতো অপারেশনগুলি হ'ল সুন্দর বেসিক সেট অপারেশন, তবে অন্তর্নির্মিত নয়। ভাগ্যক্রমে, আপনি এগুলি নিজেরাই মোটামুটি সহজেই তৈরি করতে পারেন।

সুতরাং, একত্রীকরণ ক্রিয়াকলাপটি বাস্তবায়নের জন্য (এক সেটের সামগ্রীগুলিকে অন্য একটিতে বা একটি মানচিত্রে অন্য একত্রে মার্জ করা) আপনি একক .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);
});

অথবা, ES6 সিনট্যাক্সে:

t.forEach((value, key) => s.set(key, value));

এফওয়াইআই, যদি আপনি কোনও বিল্ট-ইন Setঅবজেক্টের কোনও সাধারণ সাবক্লাস চান যাতে কোনও .merge()পদ্ধতি থাকে তবে আপনি এটি ব্যবহার করতে পারেন:

// subclass of Set that adds new methods
// Except where otherwise noted, arguments to methods
//   can be a Set, anything derived from it or an Array
// Any method that returns a new Set returns whatever class the this object is
//   allowing SetEx to be subclassed and these methods will return that subclass
//   For this to work properly, subclasses must not change behavior of SetEx methods
//
// Note that if the contructor for SetEx is passed one or more iterables, 
// it will iterate them and add the individual elements of those iterables to the Set
// If you want a Set itself added to the Set, then use the .add() method
// which remains unchanged from the original Set object.  This way you have
// a choice about how you want to add things and can do it either way.

class SetEx extends Set {
    // create a new SetEx populated with the contents of one or more iterables
    constructor(...iterables) {
        super();
        this.merge(...iterables);
    }

    // merge the items from one or more iterables into this set
    merge(...iterables) {
        for (let iterable of iterables) {
            for (let item of iterable) {
                this.add(item);
            }
        }
        return this;        
    }

    // return new SetEx object that is union of all sets passed in with the current set
    union(...sets) {
        let newSet = new this.constructor(...sets);
        newSet.merge(this);
        return newSet;
    }

    // return a new SetEx that contains the items that are in both sets
    intersect(target) {
        let newSet = new this.constructor();
        for (let item of this) {
            if (target.has(item)) {
                newSet.add(item);
            }
        }
        return newSet;        
    }

    // return a new SetEx that contains the items that are in this set, but not in target
    // target must be a Set (or something that supports .has(item) such as a Map)
    diff(target) {
        let newSet = new this.constructor();
        for (let item of this) {
            if (!target.has(item)) {
                newSet.add(item);
            }
        }
        return newSet;        
    }

    // target can be either a Set or an Array
    // return boolean which indicates if target set contains exactly same elements as this
    // target elements are iterated and checked for this.has(item)
    sameItems(target) {
        let tsize;
        if ("size" in target) {
            tsize = target.size;
        } else if ("length" in target) {
            tsize = target.length;
        } else {
            throw new TypeError("target must be an iterable like a Set with .size or .length");
        }
        if (tsize !== this.size) {
            return false;
        }
        for (let item of target) {
            if (!this.has(item)) {
                return false;
            }
        }
        return true;
    }
}

module.exports = SetEx;

এটি তার নিজের ফাইল setex.js এর মধ্যে থাকা যা আপনি তারপরে নোড.জেজে andুকে require()বিল্ট-ইন সেটের জায়গায় ব্যবহার করতে পারবেন ।


3
ভাবি না new Set(s, t)। কাজ করে। tপরামিতি উপেক্ষা করা হয়। এছাড়াও, addএটির প্যারামিটারের ধরনটি সনাক্ত করা এবং কোনও সেট যদি সেটের উপাদানগুলিকে যুক্ত করে তবে স্পষ্টত যুক্তিসঙ্গত আচরণ নয় কারণ সেটে কোনও সেট নিজেকে যুক্ত করার কোনও উপায় থাকবে না।

@ টোরাজাবুরো - .add()একটি সেট নেওয়ার পদ্ধতি হিসাবে , আমি আপনার বক্তব্যটি বুঝতে পারি। আমি কেবল .add()সেট বা সংযোজনগুলির প্রয়োজনের আগে কখনও কখনও সেট ব্যবহার করে সেটগুলি একত্রিত করতে সক্ষম হওয়ার চেয়ে কম ব্যবহারের সন্ধান পেয়েছি, তবে আমার অনেকবার সেটগুলি মার্জ করার দরকার পড়েছিল। একটি ব্যবহারের তুলনায় অন্যটির ব্যবহারের মতামতের বিষয়।
jਫਰ00

আরগ, আমি ঘৃণা করি যে n.forEach(m.add, m)এটি মানচিত্রের জন্য কাজ করে না: - এটি কী / মান জোড়া উল্টায়!
বার্গি

@ বার্গি - হ্যাঁ, এটি অদ্ভুত Map.prototype.forEach()এবং Map.prototype.set()যুক্তিগুলি বিপরীত করেছে। কারও মতামত দেখে মনে হচ্ছে। এটি এক সাথে ব্যবহার করার চেষ্টা করার সময় আরও কোড জোর করে।
jender00

@ jender00: ওটিওহ, এটাই বোঝা যায়। setপরামিতি অর্ডার কী / মান জোড়া জন্য প্রাকৃতিক হয়, forEachসঙ্গে সংযুক্ত করা হয় Arrayগুলি forEach(এবং ভালো জিনিস পদ্ধতি $.eachবা _.eachযে গনা বস্তু)।
বার্গি

20

সম্পাদনা করুন :

আমি অন্যান্য সমাধানগুলির বিপরীতে আমার মূল সমাধানটি বেঞ্চমার্ক করেছি এবং দেখতে পেয়েছি যে এটি অত্যন্ত অদক্ষ।

মানদণ্ডটি নিজেই খুব আকর্ষণীয় ( লিঙ্ক ) এটি 3 টি সমাধানের তুলনা করে (উচ্চতর ভাল):

  • @ বিফ্রেড.ইটের সমাধান যা একের পর এক মান যোগ করে (14,955 অপ / সেকেন্ড)
  • @ জেমস্লকের সমাধান, যা স্ব-চালিত জেনারেটর ব্যবহার করে (৫,০৯৯ অপ ​​/ সেকেন্ড)
  • আমার নিজস্ব, যা হ্রাস এবং ছড়িয়ে পড়ে (3,434 অপ / সেকেন্ড)

আপনি দেখতে পাচ্ছেন, @ 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}

আসল উত্তর

আমি অপারেটরটি ব্যবহার করে reduceএবং spreadঅপারেটরটিকে আরও একটি পদ্ধতির পরামর্শ দিতে চাই :

বাস্তবায়ন

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}

এটি মারাত্মকভাবে অদক্ষ।
বার্গি

1
হাই @ বেরগি, আপনি ঠিক বলেছেন। । আমার সচেতনতা (উত্থাপন জন্য ধন্যবাদ: আমি আমার সমাধান পরীক্ষিত থাকেন বিরুদ্ধে জনকে এখানে প্রস্তাব এবং নিজেকে জন্য এটি প্রমাণিত এছাড়াও, আমি আমার উত্তর এটা প্রতিফলিত করতে সম্পাদনা করেছেন দয়া করে আপনার downvote সরানোর
আসফ কাট্স

1
দুর্দান্ত, পারফরম্যান্স তুলনার জন্য ধন্যবাদ। মজাদার কীভাবে "ফলস্বরূপ" সমাধানটি দ্রুত;) এখানে উন্নতির সন্ধান করতে এখানে এসেছিলেন forofএবং addএটি কেবল খুব অদক্ষ বলে মনে হয়। আমি সত্যিই addAll(iterable)
সেটসে

1
প্রকারের সংস্করণ: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 }
শে

4
আপনার উত্তরের শীর্ষের জেএসপিফ লিংকটি ফাঁস হয়ে গেছে বলে মনে হচ্ছে। এছাড়াও, আপনি বিফ্রেডের সমাধানটি উল্লেখ করেছেন যা আমি এখানে কোথাও দেখতে পাচ্ছি না।
jender00

12

অনুমোদিত উত্তরটি দুর্দান্ত তবে এটি প্রতিবারই একটি নতুন সেট তৈরি করে।

আপনি যদি এর পরিবর্তে কোনও বিদ্যমান অবজেক্টটি রূপান্তর করতে চান তবে একটি সহায়ক ফাংশন ব্যবহার করুন।

সেট

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]

5

অ্যারে সেটগুলিতে সেটগুলি মার্জ করতে, আপনি এটি করতে পারেন

var Sets = [set1, set2, set3];

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

আমার কাছে এটি কিছুটা রহস্যজনক যে নিম্নলিখিতগুলি, যা সমমানের হওয়া উচিত, অন্তত বাবেলে ব্যর্থ হয়:

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

Array.fromঅতিরিক্ত পরামিতি নেয়, দ্বিতীয়টি ম্যাপিংয়ের কাজ। Array.prototype.mapএর কলব্যাকটিতে তিনটি আর্গুমেন্ট পাস করে: (value, index, array)সুতরাং এটি কার্যকরভাবে কল করছে Sets.map((set, index, array) => Array.from(set, index, array)। স্পষ্টতই, indexএটি একটি নম্বর এবং কোনও ম্যাপিং ফাংশন নয় তাই এটি ব্যর্থ হয়।
নিকফ

1

আসফ কাটজের জবাবের ভিত্তিতে, এখানে একটি টাইপ স্ক্রিপ্ট সংস্করণ রয়েছে:

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
}

1

এটা তোলে কোনো অর্থে দেখা যায় না ডাকতে 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()))


1

সেটগুলিকে অ্যারেতে রূপান্তর করুন, এগুলি সমতল করুন এবং শেষ পর্যন্ত নির্মাণকারী অদৃশ্য হয়ে যাবে।

const union = (...sets) => new Set(sets.map(s => [...s]).flat());

দয়া করে একটি উত্তর হিসাবে কেবল কোড পোস্ট করবেন না, তবে আপনার কোডটি কী করে এবং কীভাবে এটি সমস্যার সমস্যার সমাধান করে তা একটি ব্যাখ্যা সরবরাহ করুন। একটি ব্যাখ্যা সহ উত্তরগুলি সাধারণত উচ্চমানের হয়, এবং উন্নতদের আকর্ষণ করার সম্ভাবনা বেশি থাকে।
মার্ক রোটভিল

0

না, এগুলির জন্য কোনও বিল্টিন অপারেশন নেই তবে আপনি এগুলি সহজেই নিজের তৈরি করতে পারেন:

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;
};


2
সে যা চায় তাই করুক।
pishpish

1
প্রত্যেকে যদি তাদের যা চায় তা করে তবে আমরা অন্য ধরণের পরাজয়ের সাথে শেষ করব
বাসিন্দা

0

উদাহরণ

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']


আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.