c# - सी#में मल्टीडिमेंटल कुंजी के साथ हैशटेबल




dictionary hashtable (10)

मैं मूल रूप से सी # में दो-आयामी टाइप की गई कुंजी का उपयोग करके हैशटेबल मान तक पहुंचने का एक तरीका ढूंढ रहा हूं।

आखिर में मैं ऐसा कुछ करने में सक्षम होगा

HashTable[1][false] = 5;
int a = HashTable[1][false];
//a = 5

यही वह है जो मैं कोशिश कर रहा हूं ... काम नहीं किया है

Hashtable test = new Hashtable();
test.Add(new Dictionary<int, bool>() { { 1, true } }, 555);
Dictionary<int, bool> temp = new Dictionary<int, bool>() {{1, true}};
string testz = test[temp].ToString(); 

अगर हाल ही में कोई भी यहां है, तो यह एक उदाहरण है कि इसे नेट 4.0 में त्वरित और गंदे तरीके से कैसे करें, जैसा कि टिप्पणीकर्ताओं में से एक द्वारा वर्णित है।

class Program
{
  static void Main(string[] args)
  {
     var twoDic = new Dictionary<Tuple<int, bool>, String>();
     twoDic.Add(new Tuple<int, bool>(3, true), "3 and true." );
     twoDic.Add(new Tuple<int, bool>(4, true), "4 and true." );
     twoDic.Add(new Tuple<int, bool>(3, false), "3 and false.");

     // Will throw exception. Item with the same key already exists.
     // twoDic.Add(new Tuple<int, bool>(3, true), "3 and true." );

     Console.WriteLine(twoDic[new Tuple<int, bool>(3,false)]);
     Console.WriteLine(twoDic[new Tuple<int, bool>(4,true)]);
     // Outputs "3 and false." and "4 and true."
  }
}

अनिवार्य रूप से आपको एक एम्बेडेड हैशटेबल का उपयोग करने की आवश्यकता है। यदि आप अपने प्रश्न के बारे में सोचते हैं, तो दो चाबियों वाला हैशटेबल दो स्वतंत्र चर के साथ एक फ़ंक्शन है, और f(x,y) परिभाषा के अनुसार 2-आयामी है।

लेकिन आप इसका उपयोग करना चाहते हैं जैसे कि यह एक हैशटेबल था, और एम्बेडेड हैंश नहीं। तो आपको जो करना है वह एक ऑब्जेक्ट बनाना है जो उस एम्बेडेड हैशटेबल विचार के चारों ओर लपेटता है और एक हैश की तरह काम करता है।

कुछ स्नैग्स:

  • आप इसे फिर से चालू करना चाहते हैं, इसलिए आपको GetEnumerator() विधि को ओवरराइट करने की आवश्यकता है। और आपको अपने खुद के इटरेटर की आवश्यकता है जो 2 आयामों में सही ढंग से पुनरावृत्त होगा।
  • आपको यह सुनिश्चित करने के लिए और अधिक जांच करने की आवश्यकता है कि कोई डुप्लीकेट नहीं है।

मैंने इसे करने के लिए अपना कोड शामिल किया है:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Windows.Forms;

namespace YourProjectNameHere
{
    public class Hashtable2D
    {
        /// <summary>
        /// This is a hashtable of hashtables
        /// The X dim is the root key, and the y is the internal hashes key
        /// </summary>
        /// 
        private Hashtable root = new Hashtable();
        public bool overwriteDuplicates = false;
        public bool alertOnDuplicates = true;

        public void Add(object key_x, object key_y, object toStore)
        {
            if(root[key_x]!=null)//If key_x has already been entered 
            {
                Hashtable tempHT = (Hashtable)root[key_x];//IF the hash table does not exist then focus will skip to the catch statement
                if (tempHT[key_y] == null)  tempHT.Add(key_y, toStore);
                else handleDuplicate(tempHT, key_y, toStore);
            }else{//Making a new hashtable 
                Hashtable tempHT = new Hashtable();
                tempHT.Add(key_y, toStore);
                root.Add(key_x, tempHT);
            }

        }

        public void Remove(object key_x, object key_y)
        {
            try{
                ((Hashtable)root[key_x]).Remove(key_y);
            }catch(Exception e){
                MessageBox.Show("That item does not exist");
            }

        }

        public void handleDuplicate (Hashtable tempHT, object key_y, object toStore)
        {
            if (alertOnDuplicates) MessageBox.Show("This Item already Exists in the collection");

            if (overwriteDuplicates)
            {
                tempHT.Remove(key_y);
                tempHT.Add(key_y,toStore);
            }
        }

        public object getItem(object key_x, object key_y)
        {
            Hashtable tempHT = (Hashtable)root[key_x];
            return tempHT[key_y];
        }

        public ClassEnumerator GetEnumerator()
        {
            return new ClassEnumerator(root);
        }

        public class ClassEnumerator : IEnumerator
        {
            private Hashtable ht;
            private IEnumerator iEnumRoot;
            private Hashtable innerHt;
            private IEnumerator iEnumInner;

            public ClassEnumerator(Hashtable _ht)
            {
                ht = _ht;
                iEnumRoot = ht.GetEnumerator();

                iEnumRoot.MoveNext();//THIS ASSUMES THAT THERE IS AT LEAST ONE ITEM

                innerHt = (Hashtable)((DictionaryEntry)iEnumRoot.Current).Value;
                iEnumInner = innerHt.GetEnumerator();
            }

            #region IEnumerator Members

            public void Reset()
            {
                iEnumRoot = ht.GetEnumerator();
            }

            public object Current
            {
                get
                {
                    return iEnumInner.Current; 
                }
            }

            public bool MoveNext()
            {
                if(!iEnumInner.MoveNext())
                {
                    if (!iEnumRoot.MoveNext()) return false;
                    innerHt = (Hashtable)((DictionaryEntry)iEnumRoot.Current).Value;
                    iEnumInner = innerHt.GetEnumerator();
                    iEnumInner.MoveNext();
                }
                return true;
            }

            #endregion
        }

    }
}

आप अपने हैशटेबल्स को "डबल-नेस्ट" करने में सक्षम हो सकते हैं - दूसरे शब्दों में, आपका मुख्य शब्दकोश प्रकार का Dictionary<int, Dictionary<bool, my_return_type>>

यह आपके पहले कोड स्निपेट में डबल ब्रैकेट नोटेशन का उपयोग करने में सक्षम होने का लक्ष्य पूरा करता है।

बेशक, प्रबंधन पक्ष थोड़ा सा ट्रिकियर है। प्रत्येक बार जब आप एक एंट्री जोड़ते हैं, तो आपको यह जांचने की ज़रूरत है कि क्या मुख्य शब्दकोष में प्राथमिक कुंजी के लिए एक शब्दकोश है, और यदि नहीं, तो एक नया शब्दकोश जोड़ें, फिर आंतरिक शब्दकोश में द्वितीयक कुंजी और मान जोड़ें।


आप इसे नए tuples के साथ अब सी # 7.0 में कर सकते हैं:

// Declare
var test = new Dictionary<(int, bool), int>();

// Add
test.Add((1, false), 5);

// Get
int a = test[(1, false)];

एक कुंजी के रूप में किसी प्रकार की ट्यूपल संरचना के साथ एक नियमित शब्दकोश का उपयोग करने के बारे में कैसे?

public class TwoKeyDictionary<K1,K2,V>
{
    private readonly Dictionary<Pair<K1,K2>, V> _dict;

    public V this[K1 k1, K2 k2]
    {
        get { return _dict[new Pair(k1,k2)]; }
    }

    private struct Pair
    {
        public K1 First;
        public K2 Second;

        public override Int32 GetHashCode()
        {
            return First.GetHashCode() ^ Second.GetHashCode();
        }

        // ... Equals, ctor, etc...
    }
}

क्या आप एक Dictionary<KeyValuePair<int,bool>,int> उपयोग कर सकते हैं?


देखो, यह कोड ठीक काम करता है:

    public Form1()
    {
            InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {

        this.Services = new Dictionary<object, Hashtable>();
        this.Services.Add("array1", new Hashtable());

        this.Services["array1"]["qwe"] = "123";
        this.Services["array1"][22] = 223;

        object zz = null;
        zz = this.Services["array1"]["qwe"];
        MessageBox.Show(zz.ToString()); // shows qwe

        zz = this.Services["array1"][22];
        MessageBox.Show(zz.ToString()); // shows 22
    }

मैन्युअल रूप से ऐसा करने से बचने के लिए अब हमें केवल एक रैपर की आवश्यकता है। सेवा। जोड़ें ("array1", नया हैशटेबल ());


मुझे लगता है कि एक बेहतर तरीका है कि आप अपनी बहु-आयामी कुंजी के कई क्षेत्रों को कक्षा / संरचना में शामिल कर सकें। उदाहरण के लिए

struct Key {
  public readonly int Dimension1;
  public readonly bool Dimension2;
  public Key(int p1, bool p2) {
    Dimension1 = p1;
    Dimension2 = p2;
  }
  // Equals and GetHashCode ommitted
}

अब आप एक सामान्य हैशटेबल बना सकते हैं और उपयोग कर सकते हैं और इस रैपर को कुंजी के रूप में उपयोग कर सकते हैं।


मैं jachymko के समाधान पर थोड़ी भिन्नता का सुझाव दूंगा जो आपको कुंजी जोड़े के लिए कक्षा बनाने से बचने की अनुमति देगा। इसके बजाए, शब्दकोशों का एक निजी शब्दकोश लपेटें, जैसा कि:

public class MultiDictionary<K1, K2, V>
{
    private Dictionary<K1, Dictionary<K2, V>> dict = 
        new Dictionary<K1, Dictionary<K2, V>>();

    public V this[K1 key1, K2 key2]
    {
        get
        {
            return dict[key1][key2];
        }

        set
        {
            if (!dict.ContainsKey(key1))
            {
                dict[key1] = new Dictionary<K2, V>();
            }
            dict[key1][key2] = value;
        }
    }
}

मैं सुझाव दूंगा कि आप बूल और int गुणों को उजागर करने वाली एक छोटी सी कस्टम क्लास बनाएं, और इसके गेटहाशकोड और बराबर विधियों को ओवरराइड करें, फिर इसे कुंजी के रूप में उपयोग करें।





hashtable