সি # তে অভিধান কী হিসাবে টিপলস (বা অ্যারে)


109

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

উত্তর:


114

আপনি। নেট 4.0 এ থাকলে একটি টিপল ব্যবহার করুন:

lookup = new Dictionary<Tuple<TypeA, TypeB, TypeC>, string>();

যদি না হয় আপনি একটি টিপল সংজ্ঞায়িত করতে পারেন এবং এটি কী হিসাবে ব্যবহার করতে পারেন। টিপলকে গেটহ্যাশকোড, সমান এবং আইকোয়েটেবলকে ওভাররাইড করতে হবে:

struct Tuple<T, U, W> : IEquatable<Tuple<T,U,W>>
{
    readonly T first;
    readonly U second;
    readonly W third;

    public Tuple(T first, U second, W third)
    {
        this.first = first;
        this.second = second;
        this.third = third;
    }

    public T First { get { return first; } }
    public U Second { get { return second; } }
    public W Third { get { return third; } }

    public override int GetHashCode()
    {
        return first.GetHashCode() ^ second.GetHashCode() ^ third.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        if (obj == null || GetType() != obj.GetType())
        {
            return false;
        }
        return Equals((Tuple<T, U, W>)obj);
    }

    public bool Equals(Tuple<T, U, W> other)
    {
        return other.first.Equals(first) && other.second.Equals(second) && other.third.Equals(third);
    }
}

6
এই কাঠামোর জন্য আইকুয়েটেবল <টিপল <টি, ইউ, ডাব্লু >> প্রয়োগ করা উচিত। হ্যাশ কোডের সংঘর্ষের ক্ষেত্রে যখন সমান () কল করা হয় তখন আপনি বক্সিংটি এড়াতে পারবেন।
ডাস্টিন ক্যাম্পবেল

16
@ জেরিজেভিএল এবং অন্য যে কেউ আমার মতো গুগলের দ্বারা এটি খুঁজে পায়,। নেট 4 এর টিপল প্রয়োগগুলি সমান হয় যাতে এটি অভিধানে ব্যবহার করা যায়।
স্কট চেম্বারলাইন

30
আপনার GetHashCodeবাস্তবায়ন খুব ভাল নয়। এটি ক্ষেত্রগুলির অনুমতি অনুসারে আক্রমণকারী inv
কোডসইনচাউস

2
টিপল স্ট্রাক্ট হওয়া উচিত নয়। ফ্রেমওয়ার্কে, টুপল একটি রেফারেন্স টাইপ।
মাইকেল গ্র্যাসেক

5
@ থোরোট - অবশ্যই আপনার উদাহরণটি মিথ্যা ... এটি হওয়া উচিত। new object()অন্যের সমান হবে কেন new object()? এটি কেবল সরল রেফারেন্স কোমারিসন ব্যবহার করে না ... চেষ্টা করুন:bool test = new Tuple<int, string>(1, "foo").Equals(new Tuple<int, string>(1, "Foo".ToLower()));
মাইক মেরিনোভস্কি

35

টিপল এবং নেস্টেড ডিকশনারি ভিত্তিক পদ্ধতির মধ্যে, প্রায়শই সবসময় টিপল ভিত্তিক হয়ে যাওয়া ভাল।

রক্ষণাবেক্ষণের দৃষ্টিকোণ থেকে ,

  • দেখে মনে হচ্ছে এমন কার্যকারিতা বাস্তবায়নের পক্ষে এটি অনেক সহজ:

    var myDict = new Dictionary<Tuple<TypeA, TypeB, TypeC>, string>();

    চেয়ে

    var myDict = new Dictionary<TypeA, Dictionary<TypeB, Dictionary<TypeC, string>>>();

    আহ্বানকারী পক্ষ থেকে। দ্বিতীয় ক্ষেত্রে প্রতিটি সংযোজন, অনুসন্ধান, অপসারণ ইত্যাদির জন্য একাধিক অভিধানে ক্রিয়া প্রয়োজন।

  • তদুপরি, যদি আপনার যৌগিক কীটির ভবিষ্যতে আরও একটি (বা কম) ক্ষেত্রের প্রয়োজন হয় তবে আপনাকে দ্বিতীয় নেস্টেড ডিকশনারি এবং পরবর্তী পরীক্ষাগুলি যুক্ত করতে হবে বলে আপনাকে দ্বিতীয় ক্ষেত্রে (নেস্টেড ডিকশনারি) কোডের একটি উল্লেখযোগ্য লট পরিবর্তন করতে হবে।

পারফরম্যান্সের দৃষ্টিকোণ থেকে , আপনি নিজেরাই পরিমাপের মাধ্যমে সর্বোত্তম সিদ্ধান্তে পৌঁছতে পারেন। তবে কয়েকটি তাত্ত্বিক সীমাবদ্ধতা রয়েছে যা আপনি আগে বিবেচনা করতে পারেন:

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

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

  • Tuple পদ্ধতির সম্বন্ধে .NET tuples সবচেয়ে performant যখন তারা তার থেকে সেটে কী হিসাবে ব্যবহার করা যেতে বোঝানো করছি না Equalsএবং GetHashCodeবাস্তবায়ন কারণ মান ধরনের জন্য বক্সিং

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


পাশের নোটে, কয়েকটি কসমেটিকস অভিধানটি দুর্দান্ত করে তুলতে পারে:

  1. সূচক শৈলীর কলগুলি প্রচুর পরিচ্ছন্ন এবং স্বজ্ঞাত হতে পারে। যেমন,

    string foo = dict[a, b, c]; //lookup
    dict[a, b, c] = ""; //update/insertion

    সুতরাং আপনার অভিধান শ্রেণিতে প্রয়োজনীয় সূচকগুলি প্রকাশ করুন যা অভ্যন্তরীণভাবে সন্নিবেশ এবং লকআপগুলি পরিচালনা করে।

  2. এছাড়াও, একটি উপযুক্ত IEnumerableইন্টারফেস বাস্তবায়ন করুন এবং এমন একটি Add(TypeA, TypeB, TypeC, string)পদ্ধতি সরবরাহ করুন যা আপনাকে সংগ্রহের আর্টিমাইজার সিনট্যাক্স দেয়, যেমন:

    new MultiKeyDictionary<TypeA, TypeB, TypeC, string> 
    { 
        { a, b, c, null }, 
        ...
    };

নেস্টেড অভিধান ক্ষেত্রে, indexer আরো ভালো নাও হতে সিনট্যাক্স হবে: string foo = dict[a][b][c]?
স্টিভেন র‌্যান্ডস

@ স্টিভেনআর্যান্ডস হ্যাঁ এটি হবে।
নওফাল

1
@ নওফাল যখন আমি কীগুলির মধ্যে একটিতে সমস্ত না থাকি তখন কি আমি টুপল অভিধানটি অনুসন্ধান করতে পারি? বা আমি কি এই ডিকটি [এ, বি] এর পরে ডিক [এ, সি] এর মতো করতে পারি?
খান ইঞ্জিনিয়ার

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

যদি "কেবল একটি কী দ্বারা অনুসন্ধান করুন" এর মাধ্যমে আপনি নিজের কাছে থাকা যে কোনও কী দ্বারা মানটি ফিরে পেতে বোঝাতে চান, তবে আপনি আপনার অভিধানকে "যে কোনও মূল অভিধান" বাছাই করে আরও ভালভাবে ডিজাইন করতে পারেন। উদাহরণস্বরূপ, যদি আপনি 4উভয় কী aএবং এবং এর মান পেতে চান bতবে আপনি এটি একটি স্ট্যান্ডার্ড অভিধান করতে পারেন dict[a] = 4এবং এর মতো মান যুক্ত করতে পারেন dict[b] = 4। যৌক্তিকভাবে আপনার aএবং bএক ইউনিট হওয়া উচিত কিনা এটি বোধগম্য নয় । এই জাতীয় ক্ষেত্রে আপনি একটি কাস্টম সংজ্ঞায়িত করতে পারেন IEqualityComparerযা দুটি কী ইনস্টাসেসের সমান হিসাবে সমান হয় যদি তাদের কোনও সম্পত্তি সমান হয়। এগুলি সমস্ত পুনরায় সংশোধনের মাধ্যমে সাধারণভাবে করা যেতে পারে।
নওফাল

30

আপনি যদি সি # 7 এ থাকেন তবে আপনার সম্মিলিত কী হিসাবে মান টিপলগুলি ব্যবহার করা উচিত। মান টিউপসগুলি সাধারণত traditionalতিহ্যগত রেফারেন্স টিপলস ( Tuple<T1, …>) থেকে তুলনায় ভাল পারফরম্যান্স দেয় কারণ মান টিপলগুলি মান ধরণের (স্ট্রাক্ট) হয়, রেফারেন্স ধরণের নয়, তাই এগুলি মেমরির বরাদ্দ এবং আবর্জনা সংগ্রহের ব্যয় এড়ায়। এছাড়াও, তারা সংক্ষিপ্ত এবং আরও স্বজ্ঞাত সিন্ট্যাক্স অফার করে, যদি আপনি চান তবে তাদের ক্ষেত্রগুলির নামকরণ করার অনুমতি দেয়। তারা IEquatable<T>অভিধানের জন্য প্রয়োজনীয় ইন্টারফেসও প্রয়োগ করে ।

var dict = new Dictionary<(int PersonId, int LocationId, int SubjectId), string>();
dict.Add((3, 6, 9), "ABC");
dict.Add((PersonId: 4, LocationId: 9, SubjectId: 10), "XYZ");
var personIds = dict.Keys.Select(k => k.PersonId).Distinct().ToList();

13

ভাল, পরিষ্কার, দ্রুত, সহজ এবং পঠনযোগ্য উপায়গুলি হ'ল:

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

এই জাতীয় কিছু যুক্ত করুন:

public sealed class myKey : Tuple<TypeA, TypeB, TypeC>
{
    public myKey(TypeA dataA, TypeB dataB, TypeC dataC) : base (dataA, dataB, dataC) { }

    public TypeA DataA => Item1; 

    public TypeB DataB => Item2;

    public TypeC DataC => Item3;
}

সুতরাং আপনি এটি অভিধান সহ ব্যবহার করতে পারেন:

var myDictinaryData = new Dictionary<myKey, string>()
{
    {new myKey(1, 2, 3), "data123"},
    {new myKey(4, 5, 6), "data456"},
    {new myKey(7, 8, 9), "data789"}
};
  • আপনি এটি চুক্তিতেও ব্যবহার করতে পারেন
  • লিঙ্কে যোগদান বা গ্রুপিংয়ের কী হিসাবে
  • এভাবে আপনি কখনও আইটেম 1, আইটেম 2, আইটেম 3 এর অর্ডারটি ভুল টাইপ করেন না ...
  • কোনও জিনিস পেতে কোথায় যাবেন তা বোঝার জন্য আপনাকে মনে রাখতে বা কোডের দিকে তাকাতে হবে না
  • IStructuralEquatable, IStructuralComparable, IComparable, ITuple এগুলি সমস্ত এলরেডি ওভাররাইড করার দরকার নেই

1
এখন আপনি এক্সপ্রেশন দেহযুক্ত সদস্যদের এর আরও পরিচ্ছন্ন উদাহরণ ব্যবহার করতে পারেন যেমনpublic TypeA DataA => Item1;
অ্যান্ড্রুথাম

7

যদি কোনও কারণে আপনি সত্যিই নিজের টুপল ক্লাস তৈরি করা বা নেট নেট 4.0.০ এ ব্যবহার করা এড়াতে চান, তবে অন্য একটি পদ্ধতির সম্ভাবনা রয়েছে; আপনি তিনটি মূল মান একক মানে একত্রিত করতে পারেন।

উদাহরণস্বরূপ, যদি তিনটি মান একসাথে 64৪ টির বেশি বিট না নিয়ে পূর্ণসংখ্যার ধরণের হয় তবে আপনি এগুলিকে একটিতে সংযুক্ত করতে পারেন ulong

সবচেয়ে খারাপ ক্ষেত্রে আপনি সর্বদা একটি স্ট্রিং ব্যবহার করতে পারবেন, যতক্ষণ না আপনি নিশ্চিত হন যে এতে থাকা তিনটি উপাদান কিছু চরিত্র বা অনুক্রমের সাথে সীমিত করা হয়েছে যা কীগুলির উপাদানগুলির অভ্যন্তরে ঘটে না, উদাহরণস্বরূপ, তিনটি সংখ্যার সাহায্যে আপনি চেষ্টা করতে পারেন:

string.Format("{0}#{1}#{2}", key1, key2, key3)

এই পদ্ধতির মধ্যে অবশ্যই কিছু রচনা ওভারহেড রয়েছে তবে আপনি এটির জন্য এটি কী ব্যবহার করছেন তার উপর নির্ভর করে এটি যত্ন নেওয়ার পক্ষে যথেষ্ট তুচ্ছ হতে পারে।


6
আমি বলব যে এটি প্রসঙ্গে দৃ on়ভাবে নির্ভর করে যদিও; যদি আমার তিনটি পূর্ণ সংখ্যার টাইপ থাকে এবং পারফরম্যান্সটি সমালোচিত না হয় তবে এটি ভুল হওয়ার নূন্যতম সুযোগের সাথে পুরোপুরি ঠিকঠাক কাজ করে। অবশ্যই এইগুলি .NET 4 হিসাবে সম্পূর্ণ অপ্রয়োজনীয়, যেহেতু মাইক্রোসফ্ট আমাদের বাক্সের বাইরে মূলত (সম্ভবত সঠিক!) সরবরাহ করবে types
jerryjvl

এমনকি আপনার জন্য স্ট্রিংয়ের JavaScriptSerializerএকটি অ্যারে এবং / অথবা পূর্ণসংখ্যার ধরণের সংমিশ্রনের জন্য আপনি এই পদ্ধতিটি ব্যবহার করতে পারেন । এইভাবে, আপনাকে নিজেই একটি ডিলিমিটার চরিত্র নিয়ে আসার দরকার নেই।
বিনকি

3
এটি সত্যিকারের অগোছালো হয়ে উঠতে পারে যদি (( , )) কী (key key1, ( )) এর মধ্যে ডিলিমিনেটার ( ) থাকে সেগুলি থাকেkey2key3"#"
গ্রেগ

4

আমি আপনার টিপলটিকে সঠিক গেটহ্যাশকোড দিয়ে ওভাররাইড করব এবং কেবল এটি কী হিসাবে ব্যবহার করব।

যতক্ষণ আপনি যথাযথ পদ্ধতিগুলি ওভারলোড করেন, আপনার শালীন কর্মক্ষমতা দেখতে হবে।


1
কীভাবে কী কী কী কী সংরক্ষণ করা হয় বা অভিধান <টিকি, টিভিয়াল>> তে অবস্থিত তার উপর আইকোম্পারেবলের কোনও প্রভাব নেই। এটি সবই গেটহ্যাশকোড () এবং একটি আইকোয়ালিটি কম্পিউটারের মাধ্যমে <T> done আইক্যুয়েটেবল <টি> প্রয়োগ করা আরও ভাল পারফরম্যান্স অর্জন করবে কারণ এটি ডিফল্ট ইক্যুয়ালিটি কম্পিউটারের কারণে বক্সিংটি হ্রাস করে যা সমান (অবজেক্ট) ফাংশনে ফিরে আসে।
ডাস্টিন ক্যাম্পবেল

আমি গেটহ্যাশকোডটি উল্লেখ করতে যাচ্ছিলাম, তবে আমি ভেবেছিলাম যে অভিধানটি আইশম্পারেবল ব্যবহার করেছিল হ্যাশকোডস আইডেন্টাল ছিল ... অনুমান করি আমি ভুল ছিলাম।
জন গীটজেন

3

রেফারেন্সের জন্য এখানে নেট নেট:

[Serializable] 
public class Tuple<T1, T2, T3> : IStructuralEquatable, IStructuralComparable, IComparable, ITuple {

    private readonly T1 m_Item1; 
    private readonly T2 m_Item2;
    private readonly T3 m_Item3; 

    public T1 Item1 { get { return m_Item1; } }
    public T2 Item2 { get { return m_Item2; } }
    public T3 Item3 { get { return m_Item3; } } 

    public Tuple(T1 item1, T2 item2, T3 item3) { 
        m_Item1 = item1; 
        m_Item2 = item2;
        m_Item3 = item3; 
    }

    public override Boolean Equals(Object obj) {
        return ((IStructuralEquatable) this).Equals(obj, EqualityComparer<Object>.Default);; 
    }

    Boolean IStructuralEquatable.Equals(Object other, IEqualityComparer comparer) { 
        if (other == null) return false;

        Tuple<T1, T2, T3> objTuple = other as Tuple<T1, T2, T3>;

        if (objTuple == null) {
            return false; 
        }

        return comparer.Equals(m_Item1, objTuple.m_Item1) && comparer.Equals(m_Item2, objTuple.m_Item2) && comparer.Equals(m_Item3, objTuple.m_Item3); 
    }

    Int32 IComparable.CompareTo(Object obj) {
        return ((IStructuralComparable) this).CompareTo(obj, Comparer<Object>.Default);
    }

    Int32 IStructuralComparable.CompareTo(Object other, IComparer comparer) {
        if (other == null) return 1; 

        Tuple<T1, T2, T3> objTuple = other as Tuple<T1, T2, T3>;

        if (objTuple == null) {
            throw new ArgumentException(Environment.GetResourceString("ArgumentException_TupleIncorrectType", this.GetType().ToString()), "other");
        }

        int c = 0;

        c = comparer.Compare(m_Item1, objTuple.m_Item1); 

        if (c != 0) return c; 

        c = comparer.Compare(m_Item2, objTuple.m_Item2);

        if (c != 0) return c; 

        return comparer.Compare(m_Item3, objTuple.m_Item3); 
    } 

    public override int GetHashCode() { 
        return ((IStructuralEquatable) this).GetHashCode(EqualityComparer<Object>.Default);
    }

    Int32 IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { 
        return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1), comparer.GetHashCode(m_Item2), comparer.GetHashCode(m_Item3));
    } 

    Int32 ITuple.GetHashCode(IEqualityComparer comparer) {
        return ((IStructuralEquatable) this).GetHashCode(comparer); 
    }
    public override string ToString() {
        StringBuilder sb = new StringBuilder();
        sb.Append("("); 
        return ((ITuple)this).ToString(sb);
    } 

    string ITuple.ToString(StringBuilder sb) {
        sb.Append(m_Item1); 
        sb.Append(", ");
        sb.Append(m_Item2);
        sb.Append(", ");
        sb.Append(m_Item3); 
        sb.Append(")");
        return sb.ToString(); 
    } 

    int ITuple.Size { 
        get {
            return 3;
        }
    } 
}

3
গেটের হ্যাশ কোডটি ((আইটেম 1 ^ আইটেম 2) * 33) 3 আইটেম 3 হিসাবে প্রয়োগ করা হয়েছে
মাইকেল গ্রাচেক

2

যদি আপনার গ্রাহক কোড অভিধানের পরিবর্তে কোনও আইডি অভিধান <> ইন্টারফেস দিয়ে করতে পারেন, তবে আমার প্রবৃত্তিটি একটি কাস্টম অ্যারে তুলনাকারীর সাহায্যে একটি সোর্টার্ড ডিকোরিয়ানো <> ব্যবহার করতে পারত, যেমন:

class ArrayComparer<T> : IComparer<IList<T>>
    where T : IComparable<T>
{
    public int Compare(IList<T> x, IList<T> y)
    {
        int compare = 0;
        for (int n = 0; n < x.Count && n < y.Count; ++n)
        {
            compare = x[n].CompareTo(y[n]);
        }
        return compare;
    }
}

এবং এইভাবে তৈরি করুন (কেবলমাত্র কংক্রিট উদাহরণের জন্য ব্যবহার করে]

var dictionary = new SortedDictionary<int[], string>(new ArrayComparer<int>());
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.