জাভাস্ক্রিপ্ট সেটের জন্য অবজেক্টের সমতা কীভাবে কাস্টমাইজ করা যায়


167

নিউ ইএস 6 (হারমনি) নতুন সেট অবজেক্টের সাথে পরিচয় করিয়ে দেয় । সেট দ্বারা ব্যবহৃত পরিচয় অ্যালগরিদম ===অপারেটরের সাথে সমান এবং তাই বস্তুর তুলনা করার জন্য তেমন উপযুক্ত নয়:

var set = new Set();
set.add({a:1});
set.add({a:1});
console.log([...set.values()]); // Array [ Object, Object ]

গভীর অবজেক্টের তুলনা করতে কীভাবে সেট অবজেক্টের জন্য সাম্যতা কাস্টমাইজ করা যায়? জাভা এর মতো কিছু আছে কি equals(Object)?


3
"সামঞ্জস্য কাস্টমাইজ" বলতে কী বোঝ? জাভাস্ক্রিপ্ট অপারেটরকে অতিরিক্ত লোড করার অনুমতি দেয় না তাই অপারেটরকে ওভারলোড করার কোনও উপায় নেই ===। ES6 সেট অবজেক্টের কোনও তুলনামূলক পদ্ধতি নেই। .has()পদ্ধতি এবং .add()পদ্ধতিটি কেবল বন্ধ এটি একই প্রকৃত বস্তু বা একটি আদিম জন্য একই মান হচ্ছে হবে।
jفر00

12
"সাম্যকে কাস্টমাইজ করুন" দ্বারা আমি বিকাশকারী যে কোনও উপায়ে সমান হিসাবে বিবেচনা করা বা না বিবেচনা করার জন্য কোনও নির্দিষ্ট উপায় নির্ধারণ করতে পারে তার অর্থ।
সিজারি

উত্তর:


107

ES6 Setঅবজেক্টের কোনও তুলনা পদ্ধতি বা কাস্টম তুলনা এক্সটেনসিবিলিটি নেই।

.has(), .add()এবং .delete()পদ্ধতি শুধুমাত্র বন্ধ এটি একই প্রকৃত বস্তু বা একটি আদিম জন্য একই মান হচ্ছে কাজ এবং মধ্যে প্লাগ করার জন্য একটি উপায় আছে বা শুধু যে যুক্তি প্রতিস্থাপন না।

আপনি সম্ভবত একটি নিজস্ব Setপ্রতিস্থাপন এবং প্রতিস্থাপন থেকে আবিষ্কার করতে পারেন .has(), .add()এবং .delete()কিছু এমন একটি পদ্ধতি যা পদ্ধতিতে ইতিমধ্যে সেটটিতে রয়েছে কিনা তা আবিষ্কার করার জন্য একটি গভীর অবজেক্টের তুলনা করেছে তবে কার্যকারিতা সম্ভবত ভাল Setহবে না কারণ অন্তর্নিহিত বস্তু সাহায্য করবে না মোটেই আসল কল করার আগে আপনার নিজস্ব কাস্টম ব্যবহার করে কোনও মিল খুঁজে পেতে আপনাকে সম্ভবত সমস্ত বিদ্যমান অবজেক্টের মধ্য দিয়ে একটি জোর জোর পুনরুক্তি করতে হবে .add()

এই নিবন্ধ এবং ES6 বৈশিষ্ট্যগুলির আলোচনা থেকে এখানে কিছু তথ্য রয়েছে:

5.2 কীভাবে মানচিত্র এবং সেটগুলি কী এবং মানগুলির তুলনা করে আমি কনফিগার করতে পারি না?

প্রশ্ন: কোন মানচিত্র কীগুলি এবং কোন সেট উপাদানগুলিকে সমান বিবেচনা করা হবে তা কনফিগার করার কোনও উপায় থাকলে এটি দুর্দান্ত হবে। কেন নেই?

উত্তর: সঠিকভাবে এবং দক্ষতার সাথে প্রয়োগ করা কঠিন বলে এই বৈশিষ্ট্যটি স্থগিত করা হয়েছে। একটি বিকল্প হ'ল কলব্যাকগুলি সংগ্রহগুলিতে হস্তান্তর করা যা সমতা নির্দিষ্ট করে।

জাভাতে উপলভ্য আরেকটি বিকল্প হ'ল এমন একটি পদ্ধতির মাধ্যমে সাম্যতা নির্দিষ্ট করে যা জাভাতে বাস্তবায়ন (সমান ()) করে। যাইহোক, এই পদ্ধতির পরিবর্তনীয় অবজেক্টগুলির জন্য সমস্যাযুক্ত: সাধারণভাবে, কোনও বস্তু পরিবর্তিত হলে সংগ্রহের অভ্যন্তরে এর "অবস্থান "টিও পরিবর্তন করতে হবে। তবে জাভাতে এমন হয় না। জাভা স্ক্রিপ্ট সম্ভবত বিশেষ অপরিবর্তনীয় বস্তুর (তথাকথিত মান বস্তু) জন্য মান দ্বারা তুলনা কেবল সক্ষম করার নিরাপদ পথে যাবে। মান দ্বারা তুলনা মানে দুটি বিষয় সমান বিবেচনা করা হয় যদি তাদের বিষয়বস্তু সমান হয়। আদিম মানগুলি জাভাস্ক্রিপ্টে মান দ্বারা তুলনা করা হয়।


4
এই নির্দিষ্ট সমস্যা সম্পর্কে নিবন্ধ রেফারেন্স যুক্ত। দেখে মনে হচ্ছে চ্যালেঞ্জটি হ'ল কীভাবে কোনও সেটের সাথে কীভাবে ডিল করা যায় যা সেটে যুক্ত হওয়ার সময় অন্যটির মতো ঠিক একই রকম ছিল তবে এখন পরিবর্তন করা হয়েছে এবং সেই বস্তুর মতো আর নেই is এটা নাকি আছে Set?
jفر00

3
সরল গেটহ্যাশকোড বা অনুরূপ বাস্তবায়ন করছেন না কেন?
জাম্বি

@ জ্যাম্বি - হ্যাশ তৈরির জন্য এটি একটি আকর্ষণীয় প্রকল্প হবে যা সমস্ত প্রকারের সম্পত্তি এবং হ্যাশ বৈশিষ্ট্যগুলিকে সঠিক ক্রমে পরিচালনা করে এবং বিজ্ঞপ্তি সংক্রান্ত রেফারেন্সগুলিতে ডিল করে।
jفر00

1
@ জ্যাম্বি এমনকি একটি হ্যাশ ফাংশন সহ আপনাকে এখনও সংঘর্ষের মোকাবেলা করতে হবে। আপনি কেবল সাম্য সমস্যাটি পিছিয়ে দিচ্ছেন।
এমপেন

5
@ এমপেন এটি ঠিক নয়, আমি বিকাশকারীকে তার নির্দিষ্ট ক্লাসগুলির জন্য তার নিজস্ব হ্যাশ ফাংশন পরিচালনা করার অনুমতি দিচ্ছি যা প্রায় প্রতিটি ক্ষেত্রেই সংঘর্ষের সমস্যা প্রতিরোধ করে যেহেতু বিকাশকারী বস্তুর প্রকৃতি জানেন এবং একটি ভাল কী অর্জন করতে পারেন। অন্য যে কোনও ক্ষেত্রে, বর্তমান তুলনা পদ্ধতিতে ফলব্যাক। অনেক এর ভাষায় ইতিমধ্যে যে না, JS।
জাম্বি

28

Jender00 এর উত্তরে উল্লেখ করা হয়েছে সাম্য সম্পর্কের কাস্টমাইজেশন সম্ভবত সম্ভব নয়

নিম্নলিখিত কোডটি কম্পিউটেশনাল দক্ষ (তবে মেমরি ব্যয়বহুল) কর্মক্ষেত্রের একটি রূপরেখা উপস্থাপন করেছে :

class GeneralSet {

    constructor() {
        this.map = new Map();
        this[Symbol.iterator] = this.values;
    }

    add(item) {
        this.map.set(item.toIdString(), item);
    }

    values() {
        return this.map.values();
    }

    delete(item) {
        return this.map.delete(item.toIdString());
    }

    // ...
}

প্রতিটি elementোকানো উপাদান toIdString()স্ট্রিং ফেরত পদ্ধতি প্রয়োগ করতে হবে । দুটি অবজেক্টকে সমান বিবেচনা করা হয় যদি এবং কেবল যদি তাদের toIdStringপদ্ধতিগুলি একই মান দেয় returns


আপনিও কনস্ট্রাক্টরকে এমন একটি ফাংশন নিতে পারেন যা সমতার জন্য আইটেমগুলির তুলনা করে। আপনি যদি এই সমতাটিকে ব্যবহৃত বৈশিষ্ট্যের পরিবর্তে সেটটির বৈশিষ্ট্য হিসাবে দেখতে চান তবে এটি ভাল।
বেন জে

1
@ বেজেজে একটি স্ট্রিং উত্পন্ন করার এবং এটি একটি মানচিত্রে রাখার বিষয়টি এই যে আপনার জাভাস্ক্রিপ্ট ইঞ্জিনটি আপনার অবজেক্টের হ্যাশ মান অনুসন্ধানের জন্য নেটিভ কোডে একটি ~ O (1) অনুসন্ধান ব্যবহার করবে, যখন একটি সমতা ফাংশন গ্রহণ করার জন্য বাধ্য করা হবে সেটটির লিনিয়ার স্ক্যান করতে এবং প্রতিটি উপাদান চেক করতে।
জাম্বি

3
এই পদ্ধতির সাথে একটি চ্যালেঞ্জ হ'ল এটি আমার মনে হয় যে এটি ধরে নিয়েছে যে এর মান item.toIdString()অদম্য এবং পরিবর্তন করতে পারে না। কারণ যদি এটি করতে পারে তবে GeneralSetসহজেই এতে "নকল" আইটেমগুলি দিয়ে অবৈধ হয়ে যেতে পারে। সুতরাং, এর মতো সমাধান কেবলমাত্র নির্দিষ্ট পরিস্থিতিতে সীমাবদ্ধ থাকবে সম্ভবত সেটটি ব্যবহার করার সময় যখন বস্তুগুলি নিজেরাই পরিবর্তিত হয় না বা যেখানে সেটটি অবৈধ হয়ে যায়, তার পরিণতি হয় না। এই সমস্ত ইস্যু সম্ভবত আরও ব্যাখ্যা করে যে কেন ES6 সেট এই কার্যকারিতাটি প্রকাশ করে না কারণ এটি কেবলমাত্র নির্দিষ্ট পরিস্থিতিতে কাজ করে।
jفر00

.delete()এই উত্তরের সঠিক বাস্তবায়ন যুক্ত করা সম্ভব ?
jlewkovich

1
@ জেলেভকোভিচ নিশ্চিত
সিজারি

6

হিসাবে শীর্ষের উত্তরে উল্লেখ করা হয়েছে, সাম্যকে অনুকূলিতকরণ করা পরিবর্তনীয় বস্তুর জন্য সমস্যাযুক্ত। সুসংবাদটি হ'ল (এবং এখনও অবাক হয়ে কেউ এটি উল্লেখ করেন নি) অপরিবর্তনীয়-জেএস নামে একটি খুব জনপ্রিয় গ্রন্থাগার রয়েছে যা অপরিবর্তনীয় ধরণের একটি সমৃদ্ধ সেট সরবরাহ করে যা আপনি খুঁজছেন গভীর মান সমতা শব্দার্থক সরবরাহ করে

অপরিবর্তনীয়-জেএস ব্যবহার করে আপনার উদাহরণ এখানে :

const { Map, Set } = require('immutable');
var set = new Set();
set = set.add(Map({a:1}));
set = set.add(Map({a:1}));
console.log([...set.values()]); // [Map {"a" => 1}]

10
স্থায়ী-জেএস সেট / মানচিত্রের পারফরম্যান্স কীভাবে দেশী সেট / মানচিত্রের সাথে তুলনা করে?
ফ্রাঙ্কস্টার

5

এখানে উত্তর যুক্ত করতে, আমি এগিয়ে গিয়ে একটি মানচিত্রের মোড়ক কার্যকর করেছি যা একটি কাস্টম হ্যাশ ফাংশন, একটি কাস্টম সমতা ফাংশন গ্রহণ করে এবং বালতিতে সমান (কাস্টম) হ্যাশযুক্ত স্বতন্ত্র মান সংরক্ষণ করে।

অনুমানযোগ্যভাবে, এটি সিজার্নির স্ট্রিং কনটেনটেশন পদ্ধতির চেয়ে ধীর হয়ে গেছে

সম্পূর্ণ উত্স এখানে: https://github.com/makoConstruct/ ভালু ম্যাপ


"স্ট্রিং সংযোগ"? তার পদ্ধতিটি কি আরও বেশি "স্ট্রিং সার্গেটিং" এর মতো নয় (যদি আপনি এটির নাম দিন যাচ্ছেন)? অথবা আপনি "কনটেন্টেশন" শব্দটি ব্যবহার করার কোনও কারণ আছে? আমি কৌতূহলী ;-)
বিনকি

@ বিঙ্কি এটি একটি ভাল প্রশ্ন এবং আমি মনে করি যে উত্তরটি একটি ভাল পয়েন্টটি এনেছে যে এটি বুঝতে আমার কিছুটা সময় লেগেছে। সাধারণত, একটি হ্যাশ কোড গণনা করার সময়, কেউ হ্যাশকোডবিল্ডারের মতো এমন কিছু করে যা পৃথক ক্ষেত্রের হ্যাশ কোডকে বহুগুণে পরিণত করে এবং অনন্য হওয়ার গ্যারান্টিযুক্ত হয় না (সুতরাং একটি কাস্টম সমতা ফাংশনের প্রয়োজন)। যাইহোক, একটি আইডি স্ট্রিং তৈরি করার সময় আপনি স্বতন্ত্র ক্ষেত্রের আইডি স্ট্রিংগুলি স্বতন্ত্র
পেস

সুতরাং আপনার যদি একটি Pointসংজ্ঞায়িত থাকে { x: number, y: number }তবে id stringসম্ভবত আপনার x.toString() + ',' + y.toString()
পেস

আপনার সমতা তুলনা করা কিছু মান তৈরি করে যা গ্যারান্টিযুক্ত তখনই পরিবর্তিত হয় যখন জিনিসগুলি অ-সমমান বিবেচিত হওয়া উচিত আমি আগে ব্যবহার করেছি strategy বিষয়গুলি সম্পর্কে কখনও কখনও চিন্তা করা সহজ। সেক্ষেত্রে, আপনি উত্পাদন করছেনসেক্ষেত্রে হ্যাশগুলির পরিবর্তে কী । যতক্ষণ না আপনার কাছে একটি কী ডেরাইভার রয়েছে যা বিদ্যমান ফর্মগুলিতে একটি মূল কী তৈরি করে যা বিদ্যমান সরঞ্জামগুলি মান-শৈলীর সমতার সাথে সমর্থন করে যা প্রায় সবসময়ই শেষ হয় String, তখন আপনি যেমনটি বলেছিলেন তেমন পুরো হ্যাশিং এবং বকেটিং পদক্ষেপটি এড়িয়ে যেতে পারেন এবং সরাসরি সরাসরি ব্যবহার করুন Mapবা প্রাপ্ত পুরানো-শৈলীর প্লেইন অবজেক্টটি উত্পন্ন কী অনুসারে।
বিনকি

1
আপনার কী কী ডেরাইভার প্রয়োগের ক্ষেত্রে আপনি যদি সত্যই স্ট্রিং কনটেনটেশন ব্যবহার করেন তবে সাবধান হওয়ার একটি বিষয় হ'ল স্ট্রিং বৈশিষ্ট্যগুলিকে যদি কোনও মান গ্রহণের অনুমতি দেওয়া হয় তবে তাদের বিশেষ ব্যবহার করা যেতে পারে। উদাহরণস্বরূপ, যদি আপনার {x: '1,2', y: '3'}এবং থাকে {x: '1', y: '2,3'}তবে String(x) + ',' + String(y)উভয় বস্তুর জন্য একই মান আউটপুট হবে। একটি নিরাপদ বিকল্প, ধরে নিলে আপনি নির্ভর করতে পারেনJSON.stringify() , তার স্ট্রিংটি পালানোর সুবিধা নেওয়া এবং JSON.stringify([x, y])পরিবর্তে ব্যবহার করা use
বিনকি

3

তাদের সাথে সরাসরি তুলনা করা সম্ভব বলে মনে হচ্ছে না, তবে কীগুলি কেবল বাছাই করা থাকলে JSON.stringify কাজ করে। আমি যেমন একটি মন্তব্যে ইঙ্গিত করেছি

JSON.stringify ({a: 1, b: 2})! == JSON.stringify ({b: 2, a: 1});

তবে আমরা কাস্টম স্ট্রিংফাই পদ্ধতিতে এটিকে ঘিরে কাজ করতে পারি। প্রথমে আমরা পদ্ধতিটি লিখি

কাস্টম স্ট্রিংফাই

Object.prototype.stringifySorted = function(){
    let oldObj = this;
    let obj = (oldObj.length || oldObj.length === 0) ? [] : {};
    for (let key of Object.keys(this).sort((a, b) => a.localeCompare(b))) {
        let type = typeof (oldObj[key])
        if (type === 'object') {
            obj[key] = oldObj[key].stringifySorted();
        } else {
            obj[key] = oldObj[key];
        }
    }
    return JSON.stringify(obj);
}

সেট

এখন আমরা একটি সেট ব্যবহার করি। তবে আমরা বস্তুর পরিবর্তে স্ট্রিংস সেট ব্যবহার করি

let set = new Set()
set.add({a:1, b:2}.stringifySorted());

set.has({b:2, a:1}.stringifySorted());
// returns true

সমস্ত মান পান

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

let iterator = set.values();
let done = false;
while (!done) {
  let val = iterator.next();

  if (!done) {
    console.log(val.value);
  }
  done = val.done;
}

এখানে একটি ফাইলে সবার সাথে একটি লিঙ্ক's http://tpcg.io/FnJg2i


"যদি কীগুলি বাছাই করা হয়" একটি বিশেষত জটিল বস্তুগুলির জন্য যদি বড় হয়
আলেকজান্ডার মিলস

ঠিক এই কারণেই আমি এই পদ্ধতিটি বেছে নিয়েছি;)
রিয়েল.মেলোনে

2

হতে পারে আপনি ব্যবহার করার চেষ্টা করতে পারেন JSON.stringify() গভীর বস্তু তুলনা ।

উদাহরণ স্বরূপ :

const arr = [
  {name:'a', value:10},
  {name:'a', value:20},
  {name:'a', value:20},
  {name:'b', value:30},
  {name:'b', value:40},
  {name:'b', value:40}
];

const names = new Set();
const result = arr.filter(item => !names.has(JSON.stringify(item)) ? names.add(JSON.stringify(item)) : false);

console.log(result);


2
এটি কাজ করতে পারে তবে JSON.stringify ({a: 1, b: 2}) হিসাবে কাজ করতে পারে না! আপনি নিরাপদ অর্ডার। তবে সাধারণভাবে সত্যই নিরাপদ সমাধান নয়
Relif.melone

1
হ্যাঁ হ্যাঁ, "এটিকে স্ট্রিংয়ে রূপান্তর করুন"। সবকিছুর জন্য জাভাস্ক্রিপ্টের উত্তর।
টিম্ম্ম্ম

2

টাইপস্ক্রিপ্ট ব্যবহারকারীদের জন্য অন্যের উত্তরগুলি (বিশেষত সিজারি ) একটি সাধারণ টাইপ-নিরাপদ এবং পুনরায় ব্যবহারযোগ্য বেস শ্রেণিতে সাধারণীকরণ করা যেতে পারে:

/**
 * Map that stringifies the key objects in order to leverage
 * the javascript native Map and preserve key uniqueness.
 */
abstract class StringifyingMap<K, V> {
    private map = new Map<string, V>();
    private keyMap = new Map<string, K>();

    has(key: K): boolean {
        let keyString = this.stringifyKey(key);
        return this.map.has(keyString);
    }
    get(key: K): V {
        let keyString = this.stringifyKey(key);
        return this.map.get(keyString);
    }
    set(key: K, value: V): StringifyingMap<K, V> {
        let keyString = this.stringifyKey(key);
        this.map.set(keyString, value);
        this.keyMap.set(keyString, key);
        return this;
    }

    /**
     * Puts new key/value if key is absent.
     * @param key key
     * @param defaultValue default value factory
     */
    putIfAbsent(key: K, defaultValue: () => V): boolean {
        if (!this.has(key)) {
            let value = defaultValue();
            this.set(key, value);
            return true;
        }
        return false;
    }

    keys(): IterableIterator<K> {
        return this.keyMap.values();
    }

    keyList(): K[] {
        return [...this.keys()];
    }

    delete(key: K): boolean {
        let keyString = this.stringifyKey(key);
        let flag = this.map.delete(keyString);
        this.keyMap.delete(keyString);
        return flag;
    }

    clear(): void {
        this.map.clear();
        this.keyMap.clear();
    }

    size(): number {
        return this.map.size;
    }

    /**
     * Turns the `key` object to a primitive `string` for the underlying `Map`
     * @param key key to be stringified
     */
    protected abstract stringifyKey(key: K): string;
}

উদাহরণ প্রয়োগের পরে এই সহজ: কেবল stringifyKeyপদ্ধতিটি ওভাররাইড করুন । আমার ক্ষেত্রে আমি কিছু uriসম্পত্তি শক্তিশালী করি ।

class MyMap extends StringifyingMap<MyKey, MyValue> {
    protected stringifyKey(key: MyKey): string {
        return key.uri.toString();
    }
}

উদাহরণস্বরূপ ব্যবহারগুলি তখন যেমন এটি একটি নিয়মিত Map<K, V>

const key1 = new MyKey(1);
const value1 = new MyValue(1);
const value2 = new MyValue(2);

const myMap = new MyMap();
myMap.set(key1, value1);
myMap.set(key1, value2); // native Map would put another key/value pair

myMap.size(); // returns 1, not 2

-1

উভয় সেট সংমিশ্রণ থেকে একটি নতুন সেট তৈরি করুন, তারপরে দৈর্ঘ্যের তুলনা করুন।

let set1 = new Set([1, 2, 'a', 'b'])
let set2 = new Set([1, 'a', 'a', 2, 'b'])
let set4 = new Set([1, 2, 'a'])

function areSetsEqual(set1, set2) {
  const set3 = new Set([...set1], [...set2])
  return set3.size === set1.size && set3.size === set2.size
}

console.log('set1 equals set2 =', areSetsEqual(set1, set2))
console.log('set1 equals set4 =', areSetsEqual(set1, set4))

সেট 1 সমান 2 সমষ্টি = সত্য

set1 এর সমষ্টি set4 = মিথ্যা


2
এই উত্তর প্রশ্নের সাথে সম্পর্কিত? প্রশ্নটি সেট শ্রেণীর উদাহরণ হিসাবে সম্মানের সাথে আইটেমগুলির সাম্যতা সম্পর্কিত। এই প্রশ্নটি দুটি সেট দৃষ্টান্তের সমতা নিয়ে আলোচনা করবে বলে মনে হচ্ছে।
সিজারি

@czerny তুমি সঠিক - আমি প্রকৃতপক্ষে এই Stackoverflow প্রশ্ন, যেখানে উপরে পদ্ধতি ব্যবহার করা যেতে পারে দেখছেন হয়েছিল: stackoverflow.com/questions/6229197/...
স্টিফান Musarra

-2

গুগলে এই প্রশ্নটি পাওয়া যাকে (আমি হিসাবে) কী হিসাবে কোনও বস্তুর ব্যবহার করে মানচিত্রের মান পেতে চাইছে:

সতর্কতা: এই উত্তরটি সমস্ত বস্তুর সাথে কাজ করবে না

var map = new Map<string,string>();

map.set(JSON.stringify({"A":2} /*string of object as key*/), "Worked");

console.log(map.get(JSON.stringify({"A":2}))||"Not worked");

আউটপুট:

কাজ করছে

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