एक संख्यात्मक सूचकांक के माध्यम से एक Dictionary.Keys कुंजी तक पहुँचना


160

मैं एक कुंजी का एक गणना है, Dictionary<string, int>जहां उपयोग कर रहा हूं int

अब, मुझे शब्दकोश के अंदर अंतिम सम्मिलित की को एक्सेस करने की आवश्यकता है, लेकिन मुझे इसका नाम नहीं पता है। स्पष्ट प्रयास:

int LastCount = mydict[mydict.keys[mydict.keys.Count]];

काम नहीं करता है, क्योंकि Dictionary.Keysएक [] -indexer को लागू नहीं करता है।

मुझे आश्चर्य है कि क्या कोई समान वर्ग है? मैंने एक स्टैक का उपयोग करने के बारे में सोचा, लेकिन यह केवल एक स्ट्रिंग को संग्रहीत करता है। मैं अब अपनी खुद की संरचना बना सकता हूं और फिर एक का उपयोग कर सकता हूं Stack<MyStruct>, लेकिन मुझे आश्चर्य है कि क्या कोई अन्य विकल्प है, अनिवार्य रूप से एक शब्दकोश जो कि [] -इंडेक्सियर ऑन द कीज़ को लागू करता है?


1
यदि आप उस चर को बॉक्स करते हैं तो क्या होता है?
पॉल प्रीवेट

जवाबों:


222

जैसा कि @Falanwe एक टिप्पणी में बताते हैं, ऐसा कुछ करना गलत है :

int LastCount = mydict.Keys.ElementAt(mydict.Count -1);

आपको किसी शब्दकोश में कुंजियों के क्रम पर निर्भर नहीं होना चाहिए । यदि आपको आदेश देने की आवश्यकता है, तो आपको एक ऑर्डरडाउन का उपयोग करना चाहिए , जैसा कि इस उत्तर में दिया गया है । इस पृष्ठ पर अन्य उत्तर भी दिलचस्प हैं।


1
लगता है कि HashTableSystem.Collections.ICollection के साथ काम नहीं करता है 'ElementAt' के लिए परिभाषा नहीं है और कोई एक्सटेंशन विधि 'ElementAt' प्रकार के पहले तर्क को स्वीकार नहीं करती है 'System.Collections.ICollection पाया जा सकता है
v.oddou

आप ElementAtOrDefaultअपवाद रहित संस्करण के साथ काम करने के लिए संस्करण का उपयोग कर सकते हैं ।
तारिक गुग्नेर

22
यह इस तरह के गलत उत्तर को स्वीकार करने के लिए डरावना है और स्वीकार किया गया है कि बहुत कुछ। यह गलत है, क्योंकि Dictionary<TKey,TValue>प्रलेखन में कहा गया है कि "चाबियों का क्रम Dictionary<TKey, TValue>.KeyCollectionअनिर्दिष्ट है।" आदेश अपरिभाषित होने के कारण, आपके पास यह जानने का कोई तरीका नहीं है कि अंतिम स्थिति में कौन है ( mydict.Count -1)
फलांवे

यह डरावना है ... लेकिन मेरे लिए उपयोगी है क्योंकि मैं अपने संदेह की पुष्टि के लिए देख रहा था कि आप आदेश पर भरोसा नहीं कर सकते हैं !!! धन्यवाद @Falanwe
चार्ली

3
कुछ के लिए आदेश प्रासंगिक नहीं है - बस यह तथ्य कि आप सभी कुंजियों से गुजरे हैं।
रॉय मिंडेल

59

आप एक ऑर्डरडाउन का उपयोग कर सकते हैं ।

कुंजी / मूल्य जोड़े के संग्रह का प्रतिनिधित्व करता है जो कुंजी या सूचकांक द्वारा सुलभ हैं।


42
Erhm, 19 upvotes के बाद, किसी ने उल्लेख नहीं किया कि ऑर्डरड्रेड अभी भी इंडेक्स द्वारा कुंजी प्राप्त करने की अनुमति नहीं देता है?
लाजो

1
आप किसी ऑर्डर इंडेक्स के साथ पूर्णांक अनुक्रमणिका के साथ मान को एक्सेस कर सकते हैं , लेकिन एक System.Collections.Generic.SreadDictionary < TKey , TValue > के साथ, जहां सूचकांक को TKey होने की आवश्यकता है
Maxence

क्रमबद्ध नाम इस संग्रह फ़ंक्शन से संबंधित है ताकि वे उसी क्रम में तत्वों को बनाए रख सकें। कुछ मामलों में, एक आदेश का एक प्रकार के समान अर्थ होता है, लेकिन इस संग्रह में नहीं।
शारुनस बायल्किस

18

एक शब्दकोश एक हैश टेबल है, इसलिए आपको प्रविष्टि के आदेश का कोई पता नहीं है!

यदि आप अंतिम सम्मिलित कुंजी जानना चाहते हैं, तो मैं एक LastKeyInserted मूल्य शामिल करने के लिए शब्दकोश का विस्तार करने का सुझाव दूंगा।

उदाहरण के लिए:

public MyDictionary<K, T> : IDictionary<K, T>
{
    private IDictionary<K, T> _InnerDictionary;

    public K LastInsertedKey { get; set; }

    public MyDictionary()
    {
        _InnerDictionary = new Dictionary<K, T>();
    }

    #region Implementation of IDictionary

    public void Add(KeyValuePair<K, T> item)
    {
        _InnerDictionary.Add(item);
        LastInsertedKey = item.Key;

    }

    public void Add(K key, T value)
    {
        _InnerDictionary.Add(key, value);
        LastInsertedKey = key;
    }

    .... rest of IDictionary methods

    #endregion

}

आप समस्याओं में भाग लेंगे, लेकिन जब आप इसका उपयोग करेंगे .Remove()तो इसे दूर करने के लिए आपको सम्मिलित की गई सूची की एक क्रमबद्ध सूची रखनी होगी।


8

आप अंतिम कुंजी सम्मिलित संपत्ति में जोड़ने के लिए केवल शब्दकोश वर्ग का विस्तार क्यों नहीं करते हैं। निम्नलिखित की तरह कुछ हो सकता है?

public class ExtendedDictionary : Dictionary<string, int>
{
    private int lastKeyInserted = -1;

    public int LastKeyInserted
    {
        get { return lastKeyInserted; }
        set { lastKeyInserted = value; }
    }

    public void AddNew(string s, int i)
    {
        lastKeyInserted = i;

        base.Add(s, i);
    }
}

2
आप पिछले मान को अंतिम प्रविष्टि में सम्मिलित कर रहे हैं। या तो आप इसे अंतिम कुंजी डालने के लिए सेट करने के लिए थे या आपको चर और संपत्ति के लिए बेहतर नामों की आवश्यकता होगी।
फेंटियस

6

आप हमेशा ऐसा कर सकते हैं:

string[] temp = new string[mydict.count];
mydict.Keys.CopyTo(temp, 0)
int LastCount = mydict[temp[mydict.count - 1]]

लेकिन मैं इसकी सिफारिश नहीं करूंगा। इस बात की कोई गारंटी नहीं है कि अंतिम सम्मिलित कुंजी सरणी के अंत में होगी। MSDN पर कुंजी के लिए आदेश अनिर्दिष्ट है, और परिवर्तन के अधीन है। मेरे बहुत ही संक्षिप्त परीक्षण में, यह प्रविष्टि के क्रम में प्रतीत होता है, लेकिन आप स्टैक जैसी उचित बहीखाता पद्धति में बेहतर निर्माण करेंगे - जैसा कि आप सुझाव देते हैं (हालांकि मुझे आपके आधार पर एक संरचना की आवश्यकता नहीं दिखती है अन्य स्टेटमेंट) - या सिंगल वेरिएबल कैश अगर आपको सिर्फ लेटेस्ट की को जानना है।


5

मुझे लगता है कि आप इस तरह से कुछ कर सकते हैं, वाक्यविन्यास गलत हो सकता है, थोड़ी देर में C # का उपयोग किया था अंतिम आइटम प्राप्त करने के लिए

Dictionary<string, int>.KeyCollection keys = mydict.keys;
string lastKey = keys.Last();

या अधिकतम मूल्य प्राप्त करने के लिए लास्ट के बजाय मैक्स का उपयोग करें, मुझे नहीं पता कि कौन सा आपके कोड को बेहतर तरीके से फिट करता है।


2
मैं जोड़ूंगा कि चूंकि "अंतिम ()" एक विस्तार विधि है, आपको अपने .cs फ़ाइल के शीर्ष पर .NET फ्रेमवर्क 3.5 और "System.Linq" का उपयोग करने की आवश्यकता होगी।
सुपरऑली

अंतिम के लिए यह प्रयास करें (जब डिस्ट <स्ट्रिंग, स्ट्रिंग> स्पष्ट रूप से उपयोग करते हुए) :-) KeyValuePair <string, string> last = oAuthPairs.Last (); if (kvp.Key! = last.Key) {_oauth_ParamString = _oauth_ParamString + "&"; }
टिम विंडसर

4

मैं पैट्रिक के उत्तर के दूसरे भाग से सहमत हूं। यहां तक ​​कि अगर कुछ परीक्षणों में यह प्रविष्टि क्रम रखने के लिए लगता है, तो प्रलेखन (और शब्दकोशों और हैश के लिए सामान्य व्यवहार) स्पष्ट रूप से बताता है कि आदेश अनिर्दिष्ट है।

आप केवल कुंजियों के क्रम के आधार पर परेशानी पूछ रहे हैं। अपनी खुद की बहीखाता पद्धति जोड़ें (जैसा कि पैट्रिक ने कहा, अंतिम जोड़ा कुंजी के लिए सिर्फ एक चर) सुनिश्चित करने के लिए। साथ ही, डिक्शनरी पर लास्ट और मैक्स जैसे सभी तरीकों से लुभाएं नहीं क्योंकि ये संभवत: महत्वपूर्ण तुलनित्र के संबंध में हैं (मुझे इस पर यकीन नहीं है)।


4

यदि आप उस खतरनाक कोड का उपयोग करने का निर्णय लेते हैं, जो टूट-फूट के अधीन है, तो यह एक्सटेंशन फ़ंक्शन Dictionary<K,V>अपनी आंतरिक अनुक्रमण के अनुसार एक कुंजी लाएगा (जो मोनो और .NET के लिए वर्तमान में उसी क्रम में प्रतीत होता है जैसा कि आप Keysसंपत्ति की गणना करके प्राप्त करते हैं। )।

Linq का उपयोग करना बहुत बेहतर है: dict.Keys.ElementAt(i)लेकिन यह फ़ंक्शन O (N) को पुन: व्यवस्थित करेगा; निम्नलिखित O (1) है, लेकिन एक प्रतिबिंब प्रदर्शन दंड के साथ।

using System;
using System.Collections.Generic;
using System.Reflection;

public static class Extensions
{
    public static TKey KeyByIndex<TKey,TValue>(this Dictionary<TKey, TValue> dict, int idx)
    {
        Type type = typeof(Dictionary<TKey, TValue>);
        FieldInfo info = type.GetField("entries", BindingFlags.NonPublic | BindingFlags.Instance);
        if (info != null)
        {
            // .NET
            Object element = ((Array)info.GetValue(dict)).GetValue(idx);
            return (TKey)element.GetType().GetField("key", BindingFlags.Public | BindingFlags.Instance).GetValue(element);
        }
        // Mono:
        info = type.GetField("keySlots", BindingFlags.NonPublic | BindingFlags.Instance);
        return (TKey)((Array)info.GetValue(dict)).GetValue(idx);
    }
};

हम्म, जवाब में सुधार करने के लिए संपादन एक डाउनवोट अर्जित किया। क्या मैंने यह स्पष्ट नहीं किया कि कोड स्पष्ट (स्पष्ट) है, और उसी के अनुसार विचार किया जाना चाहिए?
ग्लेन स्लेडेन

4

एक विकल्प एक KeyedCollection होगा यदि कुंजी मान में एम्बेडेड है।

बस उपयोग करने के लिए एक सील वर्ग में एक बुनियादी कार्यान्वयन बनाएं।

तो बदलने के लिए Dictionary<string, int>(जो बहुत अच्छा उदाहरण नहीं है क्योंकि इंट के लिए स्पष्ट कुंजी नहीं है)।

private sealed class IntDictionary : KeyedCollection<string, int>
{
    protected override string GetKeyForItem(int item)
    {
        // The example works better when the value contains the key. It falls down a bit for a dictionary of ints.
        return item.ToString();
    }
}

KeyedCollection<string, int> intCollection = new ClassThatContainsSealedImplementation.IntDictionary();

intCollection.Add(7);

int valueByIndex = intCollection[0];

कुंजी पर आपकी टिप्पणियों के बारे में, मेरे उत्तर को इस एक पर देखें।
तक्ले

3

जिस तरह से आपने प्रश्न का उल्लेख किया है, वह मुझे विश्वास दिलाता है कि शब्दकोश में int में शब्दकोश में आइटम की "स्थिति" है। इस दावे से यह देखते हुए कि कुंजी को उस क्रम में संग्रहीत नहीं किया गया है जिसे वे जोड़ रहे हैं, यदि यह सही है, तो इसका मतलब यह होगा कि कुंजी ।Count (या .Count - 1, यदि आप शून्य-आधारित का उपयोग कर रहे हैं) तब भी होना चाहिए। हमेशा अंतिम दर्ज की गई कुंजी की संख्या हो?

यदि यह सही है, तो क्या ऐसा कोई कारण है जिसके बजाय आप शब्दकोश <int, string> का उपयोग नहीं कर सकते हैं ताकि आप mydict [mydict.Keys.Count] का उपयोग कर सकें?


2

मुझे नहीं पता कि यह काम करेगा क्योंकि मुझे पूरा यकीन है कि वे जिस क्रम में जोड़े गए हैं उस क्रम में संग्रहीत नहीं हैं, लेकिन आप एक सूची में KeysCollection डाल सकते हैं और फिर सूची में अंतिम कुंजी प्राप्त कर सकते हैं ... लेकिन यह देखने लायक होगा।

केवल एक चीज जो मैं सोच सकता हूं, वह यह है कि लुकअप सूची में कुंजियों को संग्रहीत करें और सूची में कुंजी जोड़ने से पहले उन्हें शब्दकोश में जोड़ें ... यह बहुत अच्छा नहीं है।


@ जुआन: कोई भी नहीं है। विधि () KeyCollection पर विधि
lomaxx

मैंने कोड का परीक्षण नहीं किया, लेकिन विधि [MSDN] [1] पर प्रलेखित है, हो सकता है कि इसका दूसरा संस्करण ढांचा हो? [१]: msdn.microsoft.com/en-us/library/bb908406.aspx
Juan

2 साल देर से लेकिन यह किसी की मदद कर सकता है ... नीचे जुआन की पोस्ट पर मेरा जवाब देखें। अंतिम () एक विस्तार विधि है।
सुपरऑली

2

कुंजी के संबंध में डेनियल पोस्ट और उसकी टिप्पणियों पर विस्तार करने के लिए, चूंकि कुंजी वैसे भी मूल्य के भीतर एम्बेडेड है, आप KeyValuePair<TKey, TValue>मूल्य के रूप में उपयोग कर सकते हैं । इसका मुख्य कारण यह है कि, सामान्य रूप से, कुंजी मूल्य से सीधे व्युत्पन्न नहीं है।

तो यह इस तरह दिखेगा:

public sealed class CustomDictionary<TKey, TValue>
  : KeyedCollection<TKey, KeyValuePair<TKey, TValue>>
{
  protected override TKey GetKeyForItem(KeyValuePair<TKey, TValue> item)
  {
    return item.Key;
  }
}

पिछले उदाहरण में इसका उपयोग करने के लिए, आप यह करेंगे:

CustomDictionary<string, int> custDict = new CustomDictionary<string, int>();

custDict.Add(new KeyValuePair<string, int>("key", 7));

int valueByIndex = custDict[0].Value;
int valueByKey = custDict["key"].Value;
string keyByIndex = custDict[0].Key;

2

संदर्भ के लिए अनुक्रमणिका का उपयोग करने के लिए एक शब्दकोश बहुत सहज नहीं हो सकता है लेकिन, आप KeyValuePair की एक सरणी के साथ समान संचालन कर सकते हैं :

पूर्व। KeyValuePair<string, string>[] filters;


2

आप SortedList और इसके जेनेरिक समकक्ष का भी उपयोग कर सकते हैं। इन दो वर्गों और एंड्रयू पीटर्स में उत्तर दिए गए ऑर्डरडेड वर्ज़न डिक्शनरी हैं, जिसमें आइटम को सूचकांक (स्थिति) के साथ-साथ कुंजी द्वारा पहुँचा जा सकता है। इन कक्षाओं का उपयोग कैसे करें आप पा सकते हैं: SortedList Class , SortedList Generic Class


1

दृश्य स्टूडियो के UserVoice के लिए एक लिंक प्रदान करता है सामान्य OrderedDictionary कार्यान्वयन dotmore द्वारा।

लेकिन अगर आपको सूचकांक द्वारा केवल कुंजी / मूल्य जोड़े प्राप्त करने की आवश्यकता है और कुंजी द्वारा मान प्राप्त करने की आवश्यकता नहीं है, तो आप एक सरल चाल का उपयोग कर सकते हैं। कुछ सामान्य वर्ग की घोषणा करें (मैंने इसे ListArray कहा):

class ListArray<T> : List<T[]> { }

आप इसे निर्माणकर्ताओं के साथ भी घोषित कर सकते हैं:

class ListArray<T> : List<T[]>
{
    public ListArray() : base() { }
    public ListArray(int capacity) : base(capacity) { }
}

उदाहरण के लिए, आप एक फ़ाइल से कुछ कुंजी / मूल्य जोड़े पढ़ते हैं और उन्हें केवल उसी क्रम में संग्रहीत करना चाहते हैं जिस क्रम में उन्हें पढ़ा गया है ताकि उन्हें सेवा द्वारा प्राप्त किया जा सके:

ListArray<string> settingsRead = new ListArray<string>();
using (var sr = new StreamReader(myFile))
{
    string line;
    while ((line = sr.ReadLine()) != null)
    {
        string[] keyValueStrings = line.Split(separator);
        for (int i = 0; i < keyValueStrings.Length; i++)
            keyValueStrings[i] = keyValueStrings[i].Trim();
        settingsRead.Add(keyValueStrings);
    }
}
// Later you get your key/value strings simply by index
string[] myKeyValueStrings = settingsRead[index];

जैसा कि आपने देखा होगा, जरूरी नहीं कि आप अपने ListArray में सिर्फ कुंजी / मान के जोड़े हों। आइटम एरे किसी भी लम्बाई का हो सकता है, जैसे दांतेदार सरणी में।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.