সাম্যতার জন্য হ্যাশसेट কীভাবে উপাদানগুলির তুলনা করে?


127

আমার একটি ক্লাস রয়েছে যা IComparable:

public class a : IComparable
{
    public int Id { get; set; }
    public string Name { get; set; }

    public a(int id)
    {
        this.Id = id;
    }

    public int CompareTo(object obj)
    {
        return this.Id.CompareTo(((a)obj).Id);
    }
}

যখন আমি এই শ্রেণীর অবজেক্টের একটি তালিকা একটি হ্যাশ সেটে যুক্ত করি:

a a1 = new a(1);
a a2 = new a(2);
HashSet<a> ha = new HashSet<a>();
ha.add(a1);
ha.add(a2);
ha.add(a1);

সবকিছু ঠিক নেই এবং ha.countনেই 2, কিন্তু:

a a1 = new a(1);
a a2 = new a(2);
HashSet<a> ha = new HashSet<a>();
ha.add(a1);
ha.add(a2);
ha.add(new a(1));

এখন ha.countহয় 3

  1. কেন এর পদ্ধতিকে HashSetসম্মান করে না ।aCompareTo
  2. HashSetঅনন্য অবজেক্টের তালিকা রাখার সেরা উপায় কি ?

IEqualityComparer<T>কনস্ট্রাক্টরের একটি বাস্তবায়ন যুক্ত করুন বা শ্রেণিতে এটি প্রয়োগ করুন aএমএসডিএন.মাইক্রোসফট.এইন.উস
লিবারিয়ান/

উত্তর:


137

এটি একটি ব্যবহার করে IEqualityComparer<T>(EqualityComparer<T>.Default আপনি যদি নির্মাণের ক্ষেত্রে আলাদা আলাদা উল্লেখ না করেন)।

আপনি যখন সেটে কোনও উপাদান যুক্ত করবেন, এটি ব্যবহার করে হ্যাশ কোডটি খুঁজে পাবেন IEqualityComparer<T>.GetHashCode এবং হ্যাশ কোড এবং উপাদান উভয়ই সংরক্ষণ করবে (অবশ্যই উপাদানটি ইতিমধ্যে সেটে রয়েছে কিনা তা যাচাই করার পরে)।

কোনও উপাদান সন্ধান করতে, এটি প্রথমে IEqualityComparer<T>.GetHashCodeহ্যাশ কোডটি সন্ধান করতে ব্যবহার করবে , তারপরে একই হ্যাশ কোডযুক্ত সমস্ত উপাদানগুলির জন্য এটি ব্যবহার করবেIEqualityComparer<T>.Equals প্রকৃত সাম্যের জন্য তুলনা ।

এর অর্থ আপনার কাছে দুটি বিকল্প রয়েছে:

  • IEqualityComparer<T>কনস্ট্রাক্টর একটি কাস্টম পাস । আপনি নিজেরটিকে সংশোধন করতে না পারলে Tবা আপনি যদি কোনও ডিফল্ট সমতা সম্পর্ক চান তবে এটি সর্বোত্তম বিকল্প eg এটি প্রায়শই নিজে প্রকারে প্রয়োগ করা Fooহয় না (যেমন প্রয়োগ করে নাIEqualityComparer<Foo> ) তবে একটি পৃথক প্রকারে যা কেবল তুলনার জন্য ব্যবহৃত হয়।
  • ওভাররাইড করে GetHashCodeএবং এ ধরণের ক্ষেত্রেই সমতা প্রয়োগ করুন Equals(object)। আদর্শভাবে, IEquatable<T>প্রকারটিও প্রয়োগ করুন , বিশেষত যদি এটি কোনও মান ধরণের হয়। এই পদ্ধতিগুলিকে ডিফল্ট সমতা তুলক দ্বারা ডাকা হবে।

নোট কিভাবে এই কেউই একটি পদ হয় আদেশ তুলনা - যা ইন্দ্রিয় তোলে, যেহেতু অবশ্যই পরিস্থিতিতে যেখানে আপনি সহজেই সমতা কিন্তু মোট ক্রম উল্লেখ করতে পারেন। এটি Dictionary<TKey, TValue>মূলত একই রকম ।

আপনি যদি এমন একটি সেট চান যা কেবলমাত্র সমতা তুলনার পরিবর্তে অর্ডার ব্যবহার করে, আপনি। SortedSet<T>নেট 4 ব্যবহার করতে পারেন - যা আপনাকে একটি IComparer<T>পরিবর্তে একটি নির্দিষ্ট করার অনুমতি দেয় IEqualityComparer<T>। এটি ব্যবহার করবে IComparer<T>.Compare- যা আপনি ব্যবহার করছেন IComparable<T>.CompareToবা IComparable.CompareToতা প্রতিনিধিত্ব করবে Comparer<T>.Default


7
+1 টি এছাড়াও নোট @ tyriker এর উত্তর যা তুলে ধরে লিভারেজ করার সবচেয়ে সহজ উপায় বলেন যে (যে আইএমও একটি মন্তব্য এখানে থাকা উচিত) IEqualityComparer<T>.GetHashCode/Equals()বাস্তবায়ন হয় Equalsএবং GetHashCodeউপর Tনিজেই (এবং যখন আপনি যে করছেন, আপনি শক্তিশালী ভাবে টাইপ সহযোগীর বাস্তবায়ন চাই : - bool IEquatable<T>.Equals(T other))
রুবেন বারটেলিংক

5
যদিও খুব নির্ভুলভাবে এই উত্তরটি কিছুটা বিভ্রান্তিকর হতে পারে, বিশেষত নতুন ব্যবহারকারীদের জন্য কারণ এটি পরিষ্কারভাবে বর্ণনা করে না যে সরলতম মামলার ক্ষেত্রে ওভাররাইডিং যথেষ্ট Equalsএবং GetHashCodeযথেষ্ট - যেমনটি @ টাইরিকারের উত্তরে উল্লিখিত হয়েছে।
বার্তোসকেপিপি

ইমো একবার আপনি বাস্তবায়ন IComparable(বা IComparerএই ক্ষেত্রে) আপনাকে আলাদাভাবে সাম্যতা বাস্তবায়নের জন্য বলা হবে না (তবে কেবল GetHashCode)। এক অর্থে তুলনামূলক ইন্টারফেস সমতা ইন্টারফেস থেকে উত্তরাধিকারী হওয়া উচিত। আমি দুটি পৃথক ফাংশন থাকার ক্ষেত্রে পারফরম্যান্সের সুবিধাগুলি বুঝতে পারি (যেখানে আপনি কিছু সমান বা না তা কেবল আলাদা করে সমতাকে অনুকূলিত করতে পারেন) তবে এখনও .. খুব বিভ্রান্তিকর অন্যথায় যখন আপনি নির্দিষ্ট করেছেন যখন উদাহরণগুলি CompareToকার্যকারিতা এবং কাঠামোর ক্ষেত্রে সমান হয় না যে।
নওফাল

@ নওফাল সব কিছুরই একটি যৌক্তিক আদেশ থাকে না। যদি আপনি দুটি জিনিস যে একটি bool সম্পত্তি ধারণ তুলনা করছেন এটা শুধু সাধারণ ভয়াবহ ভালো কিছু লিখতে হবে হয় a.boolProp == b.boolProp ? 1 : 0বা এটি হওয়া উচিত a.boolProp == b.boolProp ? 0 : -1বা a.boolProp == b.boolProp ? 1 : -1। Yuk!
সাইমন_উইভার

1
@ সিমন_এই যাই হোক না কেন আমি যে প্রস্তাবনা দিয়েছিলাম তা অনুমানমূলক বৈশিষ্ট্যে কোনওভাবে এড়াতে চাই না।
নওফাল

77

উত্তর ছাড়াই থাকা উত্তরটির একটি অংশে এখানে স্পষ্টতা দেওয়া হয়েছে: আপনার অবজেক্টের ধরণের HashSet<T>প্রয়োগ করতে হবে না IEqualityComparer<T>বরং তার পরিবর্তে কেবল ওভাররাইড করতে হবে Object.GetHashCode()এবং Object.Equals(Object obj)

এর পরিবর্তে:

public class a : IEqualityComparer<a>
{
  public int GetHashCode(a obj) { /* Implementation */ }
  public bool Equals(a obj1, a obj2) { /* Implementation */ }
}

তুমি এটা করো:

public class a
{
  public override int GetHashCode() { /* Implementation */ }
  public override bool Equals(object obj) { /* Implementation */ }
}

এটি সূক্ষ্ম, তবে এটি হ্যাশসেটকে যেভাবে উদ্দেশ্যযুক্ত তা কাজ করার জন্য চেষ্টা করার এক দিনের আরও ভাল অংশের জন্য আমাকে ছড়িয়ে দিয়েছে। এবং অন্যরা যেমন বলেছে, সেট করার সাথে কাজ করার সময় HashSet<a>কলিং a.GetHashCode()এবং a.Equals(obj)প্রয়োজনীয়তা শেষ হবে ।


2
ভাল যুক্তি. বিটিডব্লিউ @ জোনস্কিটের উত্তরে আমার মন্তব্যে যেমন উল্লেখ করা হয়েছে, আপনার bool IEquatable<T>.Equals(T other)সামান্য দক্ষতা অর্জনের জন্যও আরও গুরুত্বপূর্ণভাবে স্পষ্টতা বেনিফিটের জন্য বাস্তবায়ন করা উচিত । Obv কারণে প্রয়োজন ছাড়াও বাস্তবায়ন করার জন্য GetHashCodeপাশাপাশি IEquatable<T>, IEquatable <টি> জন্য ডক উল্লেখ করেছেন যে দৃঢ়তা উদ্দেশ্যে আপনার কাছে ওভাররাইড করা উচিত object.Equalsদৃঢ়তা জন্য
রুবেন Bartelink

আমি এটি বাস্তবায়নের চেষ্টা করেছি। ovveride getHashcodeকাজ, কিন্তু override bool equalsত্রুটি পায়: কোন পদ্ধতি ওভাররাইড করতে পাওয়া যায় নি। কোন ধারণা?
স্টেফানভিডস

অবশেষে যে তথ্যটি আমি সন্ধান করছিলাম ধন্যবাদ.
ম্যুরো সাম্পিয়েট্রো

উপরের উত্তরে আমার মন্তব্যগুলি থেকে - আপনার "পরিবর্তে" ক্ষেত্রে আপনার থাকতে পারে public class a : IEqualityComparer<a> {এবং তারপরেও new HashSet<a>(a)
হ্যাঙ্ককা

তবে উপরে জোন স্কিটের মন্তব্য দেখুন।
হ্যাঙ্ককা

9

HashSetব্যবহার Equalsএবং GetHashCode()

CompareTo অর্ডার সেট জন্য হয়।

আপনি যদি অনন্য অবজেক্ট চান তবে আপনি তাদের পুনরাবৃত্তির ক্রমের বিষয়ে চিন্তা করেন না, HashSet<T>এটি সাধারণত সেরা পছন্দ।


5

কনস্ট্রাক্টর হ্যাশসেট নতুন অবজেক্ট যুক্ত করার জন্য আইক্যুয়ালিম্প্যাকার প্রয়োগ করে এমন বস্তু গ্রহণ করে। যদি আপনি হ্যাশসেটে পদ্ধতিটি ব্যবহার করতে চান তবে আপনি শুদ্ধ ওভাররাইড সমান সমান, গেটহ্যাশকোড

namespace HashSet
{
    public class Employe
    {
        public Employe() {
        }

        public string Name { get; set; }

        public override string ToString()  {
            return Name;
        }

        public override bool Equals(object obj) {
            return this.Name.Equals(((Employe)obj).Name);
        }

        public override int GetHashCode() {
            return this.Name.GetHashCode();
        }
    }

    class EmployeComparer : IEqualityComparer<Employe>
    {
        public bool Equals(Employe x, Employe y)
        {
            return x.Name.Trim().ToLower().Equals(y.Name.Trim().ToLower());
        }

        public int GetHashCode(Employe obj)
        {
            return obj.Name.GetHashCode();
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            HashSet<Employe> hashSet = new HashSet<Employe>(new EmployeComparer());
            hashSet.Add(new Employe() { Name = "Nik" });
            hashSet.Add(new Employe() { Name = "Rob" });
            hashSet.Add(new Employe() { Name = "Joe" });
            Display(hashSet);
            hashSet.Add(new Employe() { Name = "Rob" });
            Display(hashSet);

            HashSet<Employe> hashSetB = new HashSet<Employe>(new EmployeComparer());
            hashSetB.Add(new Employe() { Name = "Max" });
            hashSetB.Add(new Employe() { Name = "Solomon" });
            hashSetB.Add(new Employe() { Name = "Werter" });
            hashSetB.Add(new Employe() { Name = "Rob" });
            Display(hashSetB);

            var union = hashSet.Union<Employe>(hashSetB).ToList();
            Display(union);
            var inter = hashSet.Intersect<Employe>(hashSetB).ToList();
            Display(inter);
            var except = hashSet.Except<Employe>(hashSetB).ToList();
            Display(except);

            Console.ReadKey();
        }

        static void Display(HashSet<Employe> hashSet)
        {
            if (hashSet.Count == 0)
            {
                Console.Write("Collection is Empty");
                return;
            }
            foreach (var item in hashSet)
            {
                Console.Write("{0}, ", item);
            }
            Console.Write("\n");
        }

        static void Display(List<Employe> list)
        {
            if (list.Count == 0)
            {
                Console.WriteLine("Collection is Empty");
                return;
            }
            foreach (var item in list)
            {
                Console.Write("{0}, ", item);
            }
            Console.Write("\n");
        }
    }
}

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