मूल्य से शब्दकोश कुंजी प्राप्त करें


361

C # में वैल्यू बाय डिक्शनरी कुंजी मुझे कैसे मिलेगी?

Dictionary<string, string> types = new Dictionary<string, string>()
{
            {"1", "one"},
            {"2", "two"},
            {"3", "three"}
};

मुझे कुछ इस तरह चाहिए:

getByValueKey(string value);

getByValueKey("one")वापस होना चाहिए "1"

इसका सबसे अच्छा तरीका क्या है? शायद हैशटेबल, SortedLists?


9
सटीक डुप्लिकेट: stackoverflow.com/questions/255341
गाबे

मैं इस लेख से पहले पढ़ा है, लेकिन जवाब वहाँ मिलता है।
लवजीजी

5
हां, लेकिन वहां आपको स्कीट से एक स्वीकृत जवाब मिलता है ।
रफिन

7
यहां स्वीकृत उत्तर डुप्लिकेट प्रश्न पर सब कुछ की तुलना में काफी बेहतर है। लेकिन यह सवाल पुराना है; जब जॉन ने उत्तर दिया तो शायद लंबोदर के भाव मौजूद नहीं थे।
सेठ बत्तीसिन

5
इस सवाल को फिर से एक दूसरे को संबोधित करने के बाद से। विशेष रूप से .Net 2.0, जबकि यह एक नहीं है और नेट संस्करण के वर्तमान संस्करण के लिए बेहतर उत्तर है।
राहेल

जवाबों:


645

जरूरी नहीं कि मान भी अनोखे हों ताकि आपको एक लुकअप करना पड़े। आप ऐसा कुछ कर सकते हैं:

var myKey = types.FirstOrDefault(x => x.Value == "one").Key;

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


3
@loviji: ध्यान रखें कि लूपिंग समाधान में, यदि मूल्य शब्दकोश के अंत में होता है, तो इसे खोजने के लिए अन्य सभी मूल्यों पर जाना होगा। यदि आपके पास कई प्रविष्टियाँ हैं, तो यह आपके कार्यक्रम को धीमा कर देगा।
जैच जॉनसन

2
@Zach जॉनसन: धन्यवाद। मैं आपसे सहमत हुँ। और आपका जवाब मुझे भी पसंद है। लेकिन मेरे शब्दकोश में 8-10 प्रविष्टियाँ हैं। और उन्हें गतिशील रूप से नहीं जोड़ा गया है। और मुझे लगता है, इस जवाब का उपयोग बुरा समाधान नहीं है।
बोरीजी

4
क्या मुझसे कोई चूक हो रही है? ऊपर दिया गया कोड मान लौटाता है, कुंजी नहीं। प्रकार नहीं होंगे। FirstOrDefault (x => x.Value == "one")। कुंजी अधिक उपयुक्त होगी?
फ़्लो जूल

19
सभी के लिए चेतावनी, स्वीकार किए गए उत्तर के रूप में यह संपादन के साथ खड़ा है एक अपवाद फेंक देंगे अगर FirstOrDefault कोई मैच नहीं पाता है और अशक्त वस्तु पर "कुंजी" का उपयोग करने की कोशिश करता है।
जिम यारब्रुक

11
@ जिमीबार: चूंकि KeyValuePair<Tkey,Tvalue>एक संरचना है, इसलिए एक मूल्य प्रकार, यह कभी नहीं हो सकता है nullFirstOrDefaultएक उदाहरण लौटाएगा जहाँ सभी फ़ील्ड अपने डिफ़ॉल्ट मान (जैसे nullस्ट्रिंग्स के लिए या 0 किलों के लिए) के साथ आरंभ किए जाते हैं । इसलिए आपको अपवाद नहीं मिलेगा। लेकिन आपको यह भी पता नहीं है कि क्या आपको कोई मूल्य मिला है, इसलिए यह उत्तर उस मामले को कवर नहीं करता है जो मान मौजूद नहीं है।
टिम श्मेल्टर

26

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

  1. KeyValuePair<TKey, TValue>शब्दकोश में सभी के माध्यम से पाशन करके (यदि आपके पास शब्दकोश में कई प्रविष्टियाँ हैं, तो यह एक बड़ा प्रदर्शन होगा)
  2. दो शब्दकोशों का उपयोग करें, एक मूल्य-से-कुंजी मैपिंग के लिए और दूसरा कुंजी-से-मूल्य मैपिंग के लिए (जो मेमोरी में दो बार अधिक स्थान लेगा)।

विधि 1 का उपयोग करें यदि प्रदर्शन एक विचार नहीं है, तो विधि 2 का उपयोग करें यदि स्मृति एक विचार नहीं है।

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

क्या कोई कारण है जिससे आप कुंजी-मूल्य संबंध को उलट नहीं सकते हैं?


1
प्रोग्राम को उलटा बनाने के लिए, हमें अभी भी विधि 1, सही का उपयोग करने की आवश्यकता होगी?
काइल डेलानी

यदि यह एक सामान्य घटना है तो मैं इस स्वैप के साथ-साथ आपके अंतिम प्रश्न के बारे में भी सिफारिश करूंगा।
Bonez024

3

मैं ऐसी स्थिति में था, जहां लिनक बाइंडिंग उपलब्ध नहीं थी और स्पष्ट रूप से लैम्ब्डा का विस्तार करना था। यह एक साधारण कार्य के परिणामस्वरूप हुआ:

public static T KeyByValue<T, W>(this Dictionary<T, W> dict, W val)
{
    T key = default;
    foreach (KeyValuePair<T, W> pair in dict)
    {
        if (EqualityComparer<W>.Default.Equals(pair.Value, val))
        {
            key = pair.Key;
            break;
        }
    }
    return key;
}

इसे इस तरह से कॉल करें:

public static void Main()
{
    Dictionary<string, string> dict = new Dictionary<string, string>()
    {
        {"1", "one"},
        {"2", "two"},
        {"3", "three"}
    };

    string key = KeyByValue(dict, "two");       
    Console.WriteLine("Key: " + key);
}

.NET 2.0 और अन्य सीमित वातावरण में काम करता है।


इसे एक्सटेंशन विधि के रूप में जोड़ना अधिक अच्छा है :-)
चैइम फ्रीडमैन


-1

मैंने एक डबल-लुक-अप क्लास बनाया है:

/// <summary>
/// dictionary with double key lookup
/// </summary>
/// <typeparam name="T1">primary key</typeparam>
/// <typeparam name="T2">secondary key</typeparam>
/// <typeparam name="TValue">value type</typeparam>
public class cDoubleKeyDictionary<T1, T2, TValue> {
    private struct Key2ValuePair {
        internal T2 key2;
        internal TValue value;
    }
    private Dictionary<T1, Key2ValuePair> d1 = new Dictionary<T1, Key2ValuePair>();
    private Dictionary<T2, T1> d2 = new Dictionary<T2, T1>();

    /// <summary>
    /// add item
    /// not exacly like add, mote like Dictionary[] = overwriting existing values
    /// </summary>
    /// <param name="key1"></param>
    /// <param name="key2"></param>
    public void Add(T1 key1, T2 key2, TValue value) {
        lock (d1) {
            d1[key1] = new Key2ValuePair {
                key2 = key2,
                value = value,
            };
            d2[key2] = key1;
        }
    }

    /// <summary>
    /// get key2 by key1
    /// </summary>
    /// <param name="key1"></param>
    /// <param name="key2"></param>
    /// <returns></returns>
    public bool TryGetValue(T1 key1, out TValue value) {
        if (d1.TryGetValue(key1, out Key2ValuePair kvp)) {
            value = kvp.value;
            return true;
        } else {
            value = default;
            return false;
        }
    }

    /// <summary>
    /// get key1 by key2
    /// </summary>
    /// <param name="key2"></param>
    /// <param name="key1"></param>
    /// <remarks>
    /// 2x O(1) operation
    /// </remarks>
    /// <returns></returns>
    public bool TryGetValue2(T2 key2, out TValue value) {
        if (d2.TryGetValue(key2, out T1 key1)) {
            return TryGetValue(key1, out value);
        } else {
            value = default;
            return false;
        }
    }

    /// <summary>
    /// get key1 by key2
    /// </summary>
    /// <param name="key2"></param>
    /// <param name="key1"></param>
    /// <remarks>
    /// 2x O(1) operation
    /// </remarks>
    /// <returns></returns>
    public bool TryGetKey1(T2 key2, out T1 key1) {
        return d2.TryGetValue(key2, out key1);
    }

    /// <summary>
    /// get key1 by key2
    /// </summary>
    /// <param name="key2"></param>
    /// <param name="key1"></param>
    /// <remarks>
    /// 2x O(1) operation
    /// </remarks>
    /// <returns></returns>
    public bool TryGetKey2(T1 key1, out T2 key2) {
        if (d1.TryGetValue(key1, out Key2ValuePair kvp1)) {
            key2 = kvp1.key2;
            return true;
        } else {
            key2 = default;
            return false;
        }
    }

    /// <summary>
    /// remove item by key 1
    /// </summary>
    /// <param name="key1"></param>
    public void Remove(T1 key1) {
        lock (d1) {
            if (d1.TryGetValue(key1, out Key2ValuePair kvp)) {
                d1.Remove(key1);
                d2.Remove(kvp.key2);
            }
        }
    }

    /// <summary>
    /// remove item by key 2
    /// </summary>
    /// <param name="key2"></param>
    public void Remove2(T2 key2) {
        lock (d1) {
            if (d2.TryGetValue(key2, out T1 key1)) {
                d1.Remove(key1);
                d2.Remove(key2);
            }
        }
    }

    /// <summary>
    /// clear all items
    /// </summary>
    public void Clear() {
        lock (d1) {
            d1.Clear();
            d2.Clear();
        }
    }

    /// <summary>
    /// enumerator on key1, so we can replace Dictionary by cDoubleKeyDictionary
    /// </summary>
    /// <param name="key1"></param>
    /// <returns></returns>
    public TValue this[T1 key1] {
        get => d1[key1].value;
    }

    /// <summary>
    /// enumerator on key1, so we can replace Dictionary by cDoubleKeyDictionary
    /// </summary>
    /// <param name="key1"></param>
    /// <returns></returns>
    public TValue this[T1 key1, T2 key2] {
        set {
            lock (d1) {
                d1[key1] = new Key2ValuePair {
                    key2 = key2,
                    value = value,
                };
                d2[key2] = key1;
            }
        }
    }

-3
types.Values.ToList().IndexOf("one");

Values.ToList () आपके शब्दकोश मूल्यों को वस्तुओं की सूची में परिवर्तित करता है। IndexOf ("एक") "एक" की तलाश में आपकी नई सूची खोजता है और वह इंडेक्स लौटाता है जो शब्दकोश में कुंजी / मान युग्म के सूचकांक से मेल खाता है।

यह विधि शब्दकोश कुंजी के बारे में परवाह नहीं करती है, यह केवल उस मूल्य के सूचकांक को वापस करती है जिसे आप खोज रहे हैं।

ध्यान रखें कि आपके शब्दकोश में एक से अधिक "एक" मूल्य हो सकते हैं। और यही कारण है कि कोई "कुंजी प्राप्त करें" विधि नहीं है।


-4

नीचे कोड केवल तभी काम करता है जब उसमें विशिष्ट मूल्य डेटा हो

public string getKey(string Value)
{
    if (dictionary.ContainsValue(Value))
    {
        var ListValueData=new List<string>();
        var ListKeyData = new List<string>();

        var Values = dictionary.Values;
        var Keys = dictionary.Keys;

        foreach (var item in Values)
        {
            ListValueData.Add(item);
        }

        var ValueIndex = ListValueData.IndexOf(Value);
        foreach (var item in Keys)
        {
            ListKeyData.Add(item);
        }

        return  ListKeyData[ValueIndex];

    }
    return string.Empty;
}

3
-1 किसी प्रदर्शन के लिए बहुत अधिक कोड जो किमि (जो आपके 6 साल पहले पोस्ट किया गया था) के शीर्ष उत्तर से सबसे खराब होगा । आपको उन 2 सूचियों को बनाने के लिए कीस और वैल्यूज़ के गुणों को हटाने की ज़रूरत नहीं है (Linq's ToList आपके साथ ऐसा करेगा)। इसके अलावा, यदि आप IndexOf का उपयोग करने जा रहे हैं, तो आप ContainsValue पर कॉल करने से बच सकते हैं (इस प्रकार एक ही कार्य के लिए सभी तत्वों से 2 छोरों से परहेज)।
बजे मारियानो देसनज़े

2
इस सुझाव का प्रदर्शन अभी भयानक है। आप दो शब्दकोशों के साथ एक सामान्य वर्ग भी बना सकते हैं। जिनमें से एक Key1 और Key2 रखता है, और दूसरा जो Key2 और Key1 रखता है। इस तरह आप या तो कुंजी के बिना प्राप्त कर सकते हैं ... अच्छी तरह से ... वह सब कुछ जो आपके उत्तर ने सुझाया।
क्रीथिक

-12

मेरे पास ऐसा करने का बहुत सरल तरीका है। इसने मेरे लिए एकदम सही काम किया।

Dictionary<string, string> types = new Dictionary<string, string>();

types.Add("1", "one");
types.Add("2", "two");
types.Add("3", "three");

Console.WriteLine("Please type a key to show its value: ");
string rLine = Console.ReadLine();

if(types.ContainsKey(rLine))
{
    string value_For_Key = types[rLine];
    Console.WriteLine("Value for " + rLine + " is" + value_For_Key);
}

3
क्षमा करें, लेकिन आपका उत्तर प्रश्न को पूरा नहीं करता है। सवाल यह था कि मूल्य के द्वारा कुंजी कैसे खोजें, आपका उत्तर मानक दिखाता है: कुंजी द्वारा मान ढूँढना
ब्रीज़

1
पहली बार अगली बार पढ़ें
टॉमीक्स

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