জেনেরিক অভিধান কী হিসাবে কোনও বস্তুর ক্ষেত্র ব্যবহার করা


120

আমি যদি কীগুলির জন্য কী হিসাবে অবজেক্টগুলি ব্যবহার করতে চাই Dictionary , তবে নির্দিষ্ট পদ্ধতিতে তাদের তুলনা করার জন্য আমার কোন পদ্ধতিগুলি ওভাররাইডের প্রয়োজন?

বলুন আমার কাছে আ ক্লাস রয়েছে যার বৈশিষ্ট্য রয়েছে:

class Foo {
    public string Name { get; set; }
    public int FooID { get; set; }

    // elided
} 

এবং আমি একটি তৈরি করতে চাই:

Dictionary<Foo, List<Stuff>>

আমি Fooএকই সঙ্গে জিনিস চাইFooID একই গ্রুপ হিসাবে বিবেচিত হোক। Fooক্লাসে ওভাররাইড করার জন্য আমার কোন পদ্ধতিগুলির প্রয়োজন হবে ?

সংক্ষিপ্তসার হিসাবে: আমি Stuffঅবজেক্টগুলিকে শ্রেণিবদ্ধ করে তালিকাগুলিতে Fooবস্তুগুলিকে শ্রেণিবদ্ধ করতে চাই। Stuffবস্তুগুলির FooIDতাদের বিভাগে তাদের লিঙ্ক করতে একটি থাকবে ।

উত্তর:


151

ডিফল্টরূপে, দুটি গুরুত্বপূর্ণ পদ্ধতি হ'ল GetHashCode()এবং Equals()। এটি গুরুত্বপূর্ণ যে দুটি জিনিস যদি সমান হয় ( Equals()সত্য প্রত্যাবর্তন করে) তবে তাদের একই হ্যাশ কোড রয়েছে। উদাহরণস্বরূপ, আপনি "FooID ফিরিয়ে দিতে পারেন"; যেমন GetHashCode()যদি আপনি যে ম্যাচ হিসাবে চাই। আপনি বাস্তবায়ন করতে পারেন IEquatable<Foo>, তবে এটি alচ্ছিক:

class Foo : IEquatable<Foo> {
    public string Name { get; set;}
    public int FooID {get; set;}

    public override int GetHashCode() {
        return FooID;
    }
    public override bool Equals(object obj) {
        return Equals(obj as Foo);
    }
    public bool Equals(Foo obj) {
        return obj != null && obj.FooID == this.FooID;
    }
}

অবশেষে, অন্য বিকল্পটি হ'ল এটি করার জন্য সরবরাহ করা IEqualityComparer<T>


5
+1 এবং আমি এই থ্রেডটিকে হাইজ্যাক করতে চাইছি না তবে আমি এই ধারণার মধ্যে ছিলাম যে গেটহ্যাশকোড () এর FooId.GetHashCode () ফিরিয়ে দেওয়া উচিত। এটি কি সঠিক প্যাটার্ন নয়?
কেন ব্রাউনিং

8
@ কেন - ঠিক আছে, এটির জন্য কেবল এমন একটি প্রত্যাবর্তন দরকার যা প্রয়োজনীয় বৈশিষ্ট্যগুলি সরবরাহ করে। কোন FooID FooID.GetHashCode () পাশাপাশি করবে। প্রয়োগের বিশদ হিসাবে, Int32.GetHashCode () এটি "এটি রিটার্ন করুন" is অন্যান্য ধরণের (স্ট্রিং ইত্যাদি) এর জন্য, তবে হ্যাঁ: .GetHashCode () খুব কার্যকর হবে।
মার্ক গ্র্যাভেল

2
ধন্যবাদ! আমি আইকোয়ালিটি কম্পিউটারের সাথে গেলাম <T> কারণ কেবল ডিকারিওনারির জন্যই আমার ওভারডেড পদ্ধতিগুলির প্রয়োজন ছিল।
দানা

1
আপনার সচেতন হওয়া উচিত যে হ্যাশ টেবিলের উপর ভিত্তি করে ধারকগুলির কার্য সম্পাদন (অভিধান <টি>, অভিধান, হ্যাশ টেবিল ইত্যাদি) ব্যবহৃত হ্যাশ ফাংশনের মানের উপর নির্ভর করে। যদি আপনি কেবল হ্যাশ কোড হিসাবে বোকা হন তবে ধারকগুলি খুব খারাপভাবে পারফর্ম করতে পারে।
জর্জেন ফোগ

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

33

আপনি যেহেতু FooIDএই গোষ্ঠীর সনাক্তকারী হতে চান তাই আপনার Foo অবজেক্টের পরিবর্তে অভিধানে কী হিসাবে ব্যবহার করা উচিত:

Dictionary<int, List<Stuff>>

আপনি যদি Fooবিষয়টিকে কী হিসাবে ব্যবহার করেন তবে আপনি কেবল সম্পত্তি বিবেচনা করার জন্য পদ্ধতি GetHashCodeএবং Equalsপদ্ধতিটি প্রয়োগ করবেন FooIDNameসম্পত্তি যতটা Dictionaryউদ্বিগ্ন, কেবল মৃত ওজন হতে পারে , তাই আপনি কেবল Fooএকটি জন্য একটি মোড়ক হিসাবে ব্যবহার করবেনint

অতএব এটি FooIDসরাসরি মানটি ব্যবহার করা ভাল , এবং তারপরে আপনাকে কোনওটি Dictionaryইতিমধ্যে একটি ব্যবহার করে যেমন সমর্থন করে তেমন বাস্তবায়ন করতে হবে নাint কোনও কী হিসাবে ।

সম্পাদনা করুন:
আপনি যদি Fooযাইহোক ক্লাসটি কী হিসাবে ব্যবহার করতে চান তবে IEqualityComparer<Foo>এটি কার্যকর করা সহজ:

public class FooEqualityComparer : IEqualityComparer<Foo> {
   public int GetHashCode(Foo foo) { return foo.FooID.GetHashCode(); }
   public bool Equals(Foo foo1, Foo foo2) { return foo1.FooID == foo2.FooID; }
}

ব্যবহার:

Dictionary<Foo, List<Stuff>> dict = new Dictionary<Foo, List<Stuff>>(new FooEqualityComparer());

1
আরও সঠিকভাবে, ইন্ট ইতিমধ্যে কী হিসাবে ব্যবহার করার জন্য প্রয়োজনীয় পদ্ধতিগুলি / ইন্টারফেসগুলিকে সমর্থন করে। অভিধানের কোন ইন্ট বা অন্য কোনও ধরণের সরাসরি জ্ঞান নেই।
জিম মিসেল

আমি সে সম্পর্কে ভেবেছিলাম, তবে বিভিন্ন কারণে এটি ক্লিনার এবং অভিধান কীগুলি হিসাবে অবজেক্টগুলিকে ব্যবহার করা আরও সুবিধাজনক ছিল।
দানা

1
ঠিক আছে, দেখে মনে হচ্ছে আপনি কীটিকে বস্তুটি কী হিসাবে ব্যবহার করছেন, কারণ আপনি কেবল আইডিটি কী হিসাবে ব্যবহার করছেন।
গুফা

8

ফু এর জন্য আপনাকে অবজেক্টকে ওভাররাইড করতে হবে et গেটহ্যাশকোড () এবং অবজেক্ট.একুয়ালস ()

অভিধানটি প্রতিটি মানের জন্য একটি হ্যাশ বালতি গণনা করার জন্য গেটহ্যাশকোড () কে কল করবে এবং দুটি ফু এর অভিন্ন কিনা তা তুলনা করতে সমান।

ভাল হ্যাশ কোড গণনা করা নিশ্চিত করুন (একই হ্যাশকোডযুক্ত বহু সমান Foo অবজেক্টগুলি এড়ান), তবে নিশ্চিত করুন যে দুটি সমান ফুসের একই হ্যাশ কোড রয়েছে। আপনি ইক্যুয়াল-মেথড দিয়ে শুরু করতে এবং তারপরে (গেটহ্যাশকোড () এ) আপনার সমান অংশে তুলনা করা প্রতিটি সদস্যের হ্যাশ কোডটি জোর করতে পারেন।

public class Foo { 
     public string A;
     public string B;

     override bool Equals(object other) {
          var otherFoo = other as Foo;
          if (otherFoo == null)
             return false;
          return A==otherFoo.A && B ==otherFoo.B;
     }

     override int GetHashCode() {
          return 17 * A.GetHashCode() + B.GetHashCode();
     }
}

2
পাশাপাশি - তবে xor (^) হ্যাশ-কোডগুলির জন্য একটি দুর্বল সংযুক্তকারী তৈরি করে, কারণ এটি প্রায়শই প্রচুর তির্যক সংঘর্ষের দিকে পরিচালিত করে (যেমন {"ফু", "বার"} বনাম bar "বার", "ফু"}} পছন্দটি প্রতিটি পদকে গুণ এবং যোগ করা - অর্থাত্ 17 * a.GetHashCode () + B.GetHashCode ();
মার্ক গ্র্যাভেল

2
মার্ক, আমি আপনাকে বলতে চাইছি কি। তবে আপনি কীভাবে 17 নম্বর যাদুতে পাবেন? হ্যাশের সংমিশ্রনের জন্য কোনও মূল সংখ্যাটি গুণক হিসাবে ব্যবহার করা কি সুবিধাজনক? যদি তাই হয় তবে কেন?
froh42

আমি ফিরে আসার পরামর্শ দিতে পারি: (A + B) .GetHashCode () এর পরিবর্তে: 17 * A. গেটহ্যাশকোড () + বি.গেটহ্যাশকোড () এটি করবে: 1) সংঘর্ষ হওয়ার সম্ভাবনা কম এবং 2) নিশ্চিত করুন যে সেখানে কোনও নেই পূর্ণসংখ্যা ওভারফ্লো
চার্লস বার্নস

(এ + বি) .গেটহ্যাশকোড () একটি খুব খারাপ হ্যাশিং অ্যালগরিদম তৈরি করে, কারণ বিভিন্ন কক্ষে (এ, বি) একই হ্যাশের ফলস্বরূপ যদি তারা একই স্ট্রিংয়ের সাথে সংযুক্ত থাকে; "হেলো" + "নেড" হ'ল "নরক" + "মালিকানাধীন" এর সমান এবং এর ফলে একই হ্যাশ হয়।
কাসভে

@ ক্যাসভে কীভাবে (এ + "" + বি)? গেটহ্যাশকোড ()?
সময়হীন

1

Hashtableক্লাস কি !

Hashtable oMyDic = new Hashtable();
Object oAnyKeyObject = null;
Object oAnyValueObject = null;
oMyDic.Add(oAnyKeyObject, oAnyValueObject);
foreach (DictionaryEntry de in oMyDic)
{
   // Do your job
}

উপরের উপায়ে, আপনি যে কোনও বস্তু (আপনার শ্রেণীর অবজেক্ট) জেনেরিক অভিধান কী হিসাবে ব্যবহার করতে পারেন :)


1

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

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

public class Equality<T>
{
    public int GetHashCode(T classInstance)
    {
        List<FieldInfo> fields = GetFields();

        unchecked
        {
            int hash = 17;

            foreach (FieldInfo field in fields)
            {
                hash = hash * 397 + field.GetValue(classInstance).GetHashCode();
            }
            return hash;
        }
    }

    public bool Equals(T classInstance, object obj)
    {
        if (ReferenceEquals(null, obj))
        {
            return false;
        }
        if (ReferenceEquals(this, obj))
        {
            return true;
        }
        if (classInstance.GetType() != obj.GetType())
        {
            return false;
        }

        return Equals(classInstance, (T)obj);
    }

    private bool Equals(T classInstance, T otherInstance)
    {
        List<FieldInfo> fields = GetFields();

        foreach (var field in fields)
        {
            if (!field.GetValue(classInstance).Equals(field.GetValue(otherInstance)))
            {
                return false;
            }
        }

        return true;
    }

    private List<FieldInfo> GetFields()
    {
        Type myType = typeof(T);

        List<FieldInfo> fields = myType.GetTypeInfo().DeclaredFields.ToList();
        return fields;
    }
}

এটি এখানে ক্লাসে কীভাবে ব্যবহৃত হচ্ছে:

public override bool Equals(object obj)
    {
        return new Equality<ClassName>().Equals(this, obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return new Equality<ClassName>().GetHashCode(this);
        }
    }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.