Genel bir Sözlüğün belirtilen değerine sahip birden çok anahtar mı alıyorsunuz?


122

Bir anahtarın değerini bir .NET genel sözlüğünden almak kolaydır:

Dictionary<int, string> greek = new Dictionary<int, string>();
greek.Add(1, "Alpha");
greek.Add(2, "Beta");
string secondGreek = greek[2];  // Beta

Ancak bir değer verilen anahtarları almaya çalışmak o kadar kolay değildir çünkü birden fazla anahtar olabilir:

int[] betaKeys = greek.WhatDoIPutHere("Beta");  // expecting single 2

1
int[]Tek bir değer beklediğinizde neden dönüş türü ?
anar khalilov

3
@Anar, Domenic'e cevabımı oku; "Yinelenen değerler olası değildir, ancak imkansız değildir".
Dour High Arch

bir değerin anahtarı? Sanırım anahtarları
Max Hodges

Yanıtlar:


144

Pekala, işte çok yönlü versiyon:

using System;
using System.Collections.Generic;
using System.Text;

class BiDictionary<TFirst, TSecond>
{
    IDictionary<TFirst, IList<TSecond>> firstToSecond = new Dictionary<TFirst, IList<TSecond>>();
    IDictionary<TSecond, IList<TFirst>> secondToFirst = new Dictionary<TSecond, IList<TFirst>>();

    private static IList<TFirst> EmptyFirstList = new TFirst[0];
    private static IList<TSecond> EmptySecondList = new TSecond[0];

    public void Add(TFirst first, TSecond second)
    {
        IList<TFirst> firsts;
        IList<TSecond> seconds;
        if (!firstToSecond.TryGetValue(first, out seconds))
        {
            seconds = new List<TSecond>();
            firstToSecond[first] = seconds;
        }
        if (!secondToFirst.TryGetValue(second, out firsts))
        {
            firsts = new List<TFirst>();
            secondToFirst[second] = firsts;
        }
        seconds.Add(second);
        firsts.Add(first);
    }

    // Note potential ambiguity using indexers (e.g. mapping from int to int)
    // Hence the methods as well...
    public IList<TSecond> this[TFirst first]
    {
        get { return GetByFirst(first); }
    }

    public IList<TFirst> this[TSecond second]
    {
        get { return GetBySecond(second); }
    }

    public IList<TSecond> GetByFirst(TFirst first)
    {
        IList<TSecond> list;
        if (!firstToSecond.TryGetValue(first, out list))
        {
            return EmptySecondList;
        }
        return new List<TSecond>(list); // Create a copy for sanity
    }

    public IList<TFirst> GetBySecond(TSecond second)
    {
        IList<TFirst> list;
        if (!secondToFirst.TryGetValue(second, out list))
        {
            return EmptyFirstList;
        }
        return new List<TFirst>(list); // Create a copy for sanity
    }
}

class Test
{
    static void Main()
    {
        BiDictionary<int, string> greek = new BiDictionary<int, string>();
        greek.Add(1, "Alpha");
        greek.Add(2, "Beta");
        greek.Add(5, "Beta");
        ShowEntries(greek, "Alpha");
        ShowEntries(greek, "Beta");
        ShowEntries(greek, "Gamma");
    }

    static void ShowEntries(BiDictionary<int, string> dict, string key)
    {
        IList<int> values = dict[key];
        StringBuilder builder = new StringBuilder();
        foreach (int value in values)
        {
            if (builder.Length != 0)
            {
                builder.Append(", ");
            }
            builder.Append(value);
        }
        Console.WriteLine("{0}: [{1}]", key, builder);
    }
}

2
Msdn'de okuduğuma göre, bunun BiDictionary yerine BiLookup olması gerekmez mi? Önemli ya da başka bir şey değil, sadece burada bir şeyleri doğru anlayıp anlamadığımı merak ediyorum ...
Svish

Ayrıca GetByFirst'i kullandım ve EmptySecondList'i geri aldım, ona bazı şeyler ekledim ve sonra GetByFirst'i tekrar çağırdım, o zaman içinde bazı şeyler olan ve boş bir liste olmayan bir liste almaz mıydım?
Svish

@Svish: Hayır, çünkü listeye eklemeye çalıştığınızda bir istisna atar (bir diziye ekleyemezsiniz). Ve evet, BiLookup muhtemelen daha iyi bir isim olacaktır.
Jon Skeet

Bu OP'nin sorusuna yanıt verdiğini görmeme rağmen, bu biraz saf bir uygulama değil mi? Daha gerçekçi bir uygulama Sözlük <> Liste <> Sözlüğü olamaz, böylece zengin nesneleri 2 farklı anahtarla gerçekten arayabilir miydiniz?
Chris Marisic

@ChrisMarisic: Ne demek istediğinizden emin değilim - ama bunun gibi bir şey oldukça kullandım ve daha fazlasına ihtiyacım olmadı.
Jon Skeet

74

Herkesin söylediği gibi, bir sözlükte değerden anahtara hiçbir eşleştirme yoktur.

Değerden birden çok anahtara eşleme yapmak istediğinizi fark ettim - bu çözümü burada tek değerli sürüm için bırakıyorum, ancak daha sonra çok girişli çift yönlü bir harita için başka bir yanıt ekleyeceğim.

Burada benimsenmesi gereken normal yaklaşım, iki sözlüğe sahip olmaktır - biri bir yöne diğeri diğerine eşleme. Bunları ayrı bir sınıfta kapsülleyin ve yinelenen anahtar veya değeriniz olduğunda ne yapmak istediğinizi belirleyin (ör. Bir istisna atın, mevcut girişin üzerine yazın veya yeni girişi yoksayın). Şahsen ben muhtemelen bir istisna yapmaya giderdim - bu başarı davranışını tanımlamayı kolaylaştırır. Bunun gibi bir şey:

using System;
using System.Collections.Generic;

class BiDictionary<TFirst, TSecond>
{
    IDictionary<TFirst, TSecond> firstToSecond = new Dictionary<TFirst, TSecond>();
    IDictionary<TSecond, TFirst> secondToFirst = new Dictionary<TSecond, TFirst>();

    public void Add(TFirst first, TSecond second)
    {
        if (firstToSecond.ContainsKey(first) ||
            secondToFirst.ContainsKey(second))
        {
            throw new ArgumentException("Duplicate first or second");
        }
        firstToSecond.Add(first, second);
        secondToFirst.Add(second, first);
    }

    public bool TryGetByFirst(TFirst first, out TSecond second)
    {
        return firstToSecond.TryGetValue(first, out second);
    }

    public bool TryGetBySecond(TSecond second, out TFirst first)
    {
        return secondToFirst.TryGetValue(second, out first);
    }
}

class Test
{
    static void Main()
    {
        BiDictionary<int, string> greek = new BiDictionary<int, string>();
        greek.Add(1, "Alpha");
        greek.Add(2, "Beta");
        int x;
        greek.TryGetBySecond("Beta", out x);
        Console.WriteLine(x);
    }
}

1
Bunun somut bir sınıftan türetilmesi için herhangi bir neden olduğunu sanmıyorum - çok dikkatli düşünmeden kalıtımı sevmiyorum - ama kesinlikle IEnumerable vb. Uygulayabilir. Aslında, IDictionary <TFirst, TSecond> ve IDictionary uygulayabilir <TSecond, TFirst>.
Jon Skeet

1
(Her ne kadar TFirst ve TSecond aynı olsaydı bu oldukça garip olurdu ...)
Jon Skeet

6
Aslında aynı anda hem IDictionary <TFirst, TSecond> hem de IDictionary <TSecond, TFirst> uygulayamazsınız, .NET 4.0 buna izin vermez
Sebastian

2
@nawfal: Sözlük aramalarından biriAdd başarısız olacak - ancak ikincisiyse, sistemi kafa karıştırıcı bir duruma getirdik. Benim yöntemim, istisnadan sonra hala tutarlı bir koleksiyonunuz var.
Jon Skeet

1
@nawfal: Cevabı ilk yazdığımda bu yüzden mi yaptım bilmiyorum ... Tahmin ediyorum;)
Jon Skeet

26

Sözlükler aslında bu şekilde çalışmak için tasarlanmamıştır, çünkü anahtarların benzersizliği garanti edilirken, değerlerin benzersizliği garanti edilmez. Yani örneğin sahip olsaydın

var greek = new Dictionary<int, string> { { 1, "Alpha" }, { 2, "Alpha" } };

Ne için almayı beklerdin greek.WhatDoIPutHere("Alpha")?

Bu nedenle, bunun gibi bir şeyin çerçeveye eklenmesini bekleyemezsiniz. Kendi benzersiz kullanımlarınız için kendi yönteminize ihtiyacınız olacaktır --- bir dizi (veya IEnumerable<T>) döndürmek ister misiniz ? Verilen değere sahip birden fazla anahtar varsa bir istisna atmak istiyor musunuz? Ya hiç yoksa?

Şahsen, şöyle bir numaralandırmaya giderdim:

IEnumerable<TKey> KeysFromValue<TKey, TValue>(this Dictionary<TKey, TValue> dict, TValue val)
{
    if (dict == null)
    {
        throw new ArgumentNullException("dict");
    }
    return dict.Keys.Where(k => dict[k] == val);
}

var keys = greek.KeysFromValue("Beta");
int exceptionIfNotExactlyOne = greek.KeysFromValue("Beta").Single();

Zarif bir çözüm, ancak bu 2.0'da çalışmalıdır. Yinelenen değerler olası değildir, ancak imkansız değildir, bir koleksiyonu geri döndürmek daha iyi olur.
Dour Yüksek Arch

23

Linq olmadan bunu yapmanın belki de en kolay yolu çiftler arasında döngü yapmak olabilir:

int betaKey; 
foreach (KeyValuePair<int, string> pair in lookup)
{
    if (pair.Value == value)
    {
        betaKey = pair.Key; // Found
        break;
    }
}
betaKey = -1; // Not found

Linq'in olsaydı, şu şekilde kolayca yapabilirdi:

int betaKey = greek.SingleOrDefault(x => x.Value == "Beta").Key;

asık suratlı, ama yukarıda bir tür var mı ?! eminim 3.0'dasın? aşağıdaki güncellememe de bakın.
güvercin

Özür dilerim, "var" yazmayı azaltmak için kullandım. Doğrusal bir arama yapmamayı tercih ederim, sözlük büyük olabilir.
Dour Yüksek Arch

2
varbir çerçeve özelliği değil, bir dil özelliğidir. C # -6.0'dan boş birleştirme kullanabilir ve gerçekten istiyorsanız CF-2.0'ı hedeflemeye devam edebilirsiniz.
binki

3

Bir sözlük, değerlerin bir karmasını tutmaz, yalnızca anahtarları tutar, bu nedenle bir değer kullanarak üzerinde yapılan herhangi bir arama en azından doğrusal zaman alacaktır. Yapabileceğiniz en iyi şey, sözlükteki öğeleri yinelemek ve eşleşen anahtarları takip etmek veya farklı bir veri yapısına geçmek, belki de iki sözlük eşleme anahtarı-> değer ve değer-> Anahtarlar listesi bulundurmaktır. İkincisini yaparsanız, arama hızı için depolama ticareti yaparsınız. @Cybis örneğini böyle bir veri yapısına dönüştürmek fazla zaman almaz.


3

Tam teşekküllü bir İki Yönlü Sözlük (ve sadece bir Harita değil) istediğim için, onu IDictionary uyumlu bir sınıf yapmak için eksik fonksiyonları ekledim. Bu, benzersiz Anahtar-Değer Çiftlerine sahip sürüme dayanır. İstenirse dosya şu şekildedir (Çoğu iş XMLDoc aracılığıyla yapılıyordu):

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Common
{
    /// <summary>Represents a bidirectional collection of keys and values.</summary>
    /// <typeparam name="TFirst">The type of the keys in the dictionary</typeparam>
    /// <typeparam name="TSecond">The type of the values in the dictionary</typeparam>
    [System.Runtime.InteropServices.ComVisible(false)]
    [System.Diagnostics.DebuggerDisplay("Count = {Count}")]
    //[System.Diagnostics.DebuggerTypeProxy(typeof(System.Collections.Generic.Mscorlib_DictionaryDebugView<,>))]
    //[System.Reflection.DefaultMember("Item")]
    public class BiDictionary<TFirst, TSecond> : Dictionary<TFirst, TSecond>
    {
        IDictionary<TSecond, TFirst> _ValueKey = new Dictionary<TSecond, TFirst>();
        /// <summary> PropertyAccessor for Iterator over KeyValue-Relation </summary>
        public IDictionary<TFirst, TSecond> KeyValue => this;
        /// <summary> PropertyAccessor for Iterator over ValueKey-Relation </summary>
        public IDictionary<TSecond, TFirst> ValueKey => _ValueKey;

        #region Implemented members

        /// <Summary>Gets or sets the value associated with the specified key.</Summary>
        /// <param name="key">The key of the value to get or set.</param>
        /// <Returns>The value associated with the specified key. If the specified key is not found,
        ///      a get operation throws a <see cref="KeyNotFoundException"/>, and
        ///      a set operation creates a new element with the specified key.</Returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.</exception>
        /// <exception cref="T:System.Collections.Generic.KeyNotFoundException">
        /// The property is retrieved and <paramref name="key"/> does not exist in the collection.</exception>
        /// <exception cref="T:System.ArgumentException"> An element with the same key already
        /// exists in the <see cref="ValueKey"/> <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</exception>
        public new TSecond this[TFirst key]
        {
            get { return base[key]; }
            set { _ValueKey.Remove(base[key]); base[key] = value; _ValueKey.Add(value, key); }
        }

        /// <Summary>Gets or sets the key associated with the specified value.</Summary>
        /// <param name="val">The value of the key to get or set.</param>
        /// <Returns>The key associated with the specified value. If the specified value is not found,
        ///      a get operation throws a <see cref="KeyNotFoundException"/>, and
        ///      a set operation creates a new element with the specified value.</Returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="val"/> is null.</exception>
        /// <exception cref="T:System.Collections.Generic.KeyNotFoundException">
        /// The property is retrieved and <paramref name="val"/> does not exist in the collection.</exception>
        /// <exception cref="T:System.ArgumentException"> An element with the same value already
        /// exists in the <see cref="KeyValue"/> <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</exception>
        public TFirst this[TSecond val]
        {
            get { return _ValueKey[val]; }
            set { base.Remove(_ValueKey[val]); _ValueKey[val] = value; base.Add(value, val); }
        }

        /// <Summary>Adds the specified key and value to the dictionary.</Summary>
        /// <param name="key">The key of the element to add.</param>
        /// <param name="value">The value of the element to add.</param>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="key"/> or <paramref name="value"/> is null.</exception>
        /// <exception cref="T:System.ArgumentException">An element with the same key or value already exists in the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</exception>
        public new void Add(TFirst key, TSecond value) {
            base.Add(key, value);
            _ValueKey.Add(value, key);
        }

        /// <Summary>Removes all keys and values from the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</Summary>
        public new void Clear() { base.Clear(); _ValueKey.Clear(); }

        /// <Summary>Determines whether the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/> contains the specified
        ///      KeyValuePair.</Summary>
        /// <param name="item">The KeyValuePair to locate in the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</param>
        /// <Returns>true if the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/> contains an element with
        ///      the specified key which links to the specified value; otherwise, false.</Returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="item"/> is null.</exception>
        public bool Contains(KeyValuePair<TFirst, TSecond> item) => base.ContainsKey(item.Key) & _ValueKey.ContainsKey(item.Value);

        /// <Summary>Removes the specified KeyValuePair from the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</Summary>
        /// <param name="item">The KeyValuePair to remove.</param>
        /// <Returns>true if the KeyValuePair is successfully found and removed; otherwise, false. This
        ///      method returns false if <paramref name="item"/> is not found in the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</Returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="item"/> is null.</exception>
        public bool Remove(KeyValuePair<TFirst, TSecond> item) => base.Remove(item.Key) & _ValueKey.Remove(item.Value);

        /// <Summary>Removes the value with the specified key from the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</Summary>
        /// <param name="key">The key of the element to remove.</param>
        /// <Returns>true if the element is successfully found and removed; otherwise, false. This
        ///      method returns false if <paramref name="key"/> is not found in the <see cref="Dictionary&lt;TFirst,TSecond&gt;"/>.</Returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.</exception>
        public new bool Remove(TFirst key) => _ValueKey.Remove(base[key]) & base.Remove(key);

        /// <Summary>Gets the key associated with the specified value.</Summary>
        /// <param name="value">The value of the key to get.</param>
        /// <param name="key">When this method returns, contains the key associated with the specified value,
        ///      if the value is found; otherwise, the default value for the type of the key parameter.
        ///      This parameter is passed uninitialized.</param>
        /// <Returns>true if <see cref="ValueKey"/> contains an element with the specified value; 
        ///      otherwise, false.</Returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="value"/> is null.</exception>
        public bool TryGetValue(TSecond value, out TFirst key) => _ValueKey.TryGetValue(value, out key);
        #endregion
    }
}

2

gözden geçirildi: tamam bir tür bulmanız için sözlükten başka bir şeye ihtiyacınız olacaktır, çünkü eğer düşünürseniz sözlük tek yönlü anahtarlardır. yani değerler benzersiz olmayabilir

bu, c # 3.0 kullanıyormuşsunuz gibi göründüğünü söyledi, böylece döngüye başvurmak zorunda kalmayabilirsiniz ve aşağıdaki gibi bir şey kullanabilirsiniz:

var key = (from k in yourDictionary where string.Compare(k.Value, "yourValue", true)  == 0 select k.Key).FirstOrDefault();

Sözlükte .FindByValue yok. Değerler arasında geçiş yapmaktansa farklı bir veri yapısına geçmeyi tercih ederim.
Dour High Arch

2

Sözlük sınıfı bu durum için optimize edilmemiştir, ancak bunu gerçekten yapmak istiyorsanız (C # 2.0'da) şunları yapabilirsiniz:

public List<TKey> GetKeysFromValue<TKey, TVal>(Dictionary<TKey, TVal> dict, TVal val)
{
   List<TKey> ks = new List<TKey>();
   foreach(TKey k in dict.Keys)
   {
      if (dict[k] == val) { ks.Add(k); }
   }
   return ks;
}

Zarafet için LINQ çözümünü tercih ederim, ancak bu 2.0 yolu.


1

Bu işlevselliğe sahip bir Sözlük alt sınıfı oluşturamaz mısınız?


    public class MyDict < TKey, TValue > : Dictionary < TKey, TValue >
    {
        private Dictionary < TValue, TKey > _keys;

        public TValue this[TKey key]
        {
            get
            {
                return base[key];
            }
            set 
            { 
                base[key] = value;
                _keys[value] = key;
            }
        }

        public MyDict()
        {
            _keys = new Dictionary < TValue, TKey >();
        }

        public TKey GetKeyFromValue(TValue value)
        {
            return _keys[value];
        }
    }

DÜZENLEME: Üzgünüz, kodu ilk seferde doğru almadım.


Bu sadece bir anahtar için kullandığım şeyi değiştirecek ve yalnızca string anahtarının int değerini döndürecektir, her iki yönde de gitmem gerekiyor. Ve Domenic'in işaret ettiği gibi, yinelenen dize değerlerine sahip olabilirim.
Dour Yüksek Arch

İnt anahtarlarınız için yinelenen dize değerlerine sahipseniz, dizeye göre aradığınızda ne geri almayı bekliyorsunuz? Karşılık gelen int'lerin bir liste nesnesi?
Cybis

1

Burada önerilen "basit" çift yönlü sözlük çözümü karmaşıktır ve anlaşılması, sürdürülmesi veya genişletilmesi zor olabilir. Ayrıca orijinal soru "bir değerin anahtarı" için soruldu, ancak açıkça birden fazla anahtar olabilir (o zamandan beri soruyu düzenledim). Bütün yaklaşım oldukça şüpheli.

Yazılım değişiklikleri. Bakımı kolay olan kod yazmak, diğer "akıllıca" karmaşık geçici çözümlere öncelik verilmelidir. Bir sözlükteki değerlerden anahtarları geri almanın yolu döngüdür. Sözlük çift yönlü olacak şekilde tasarlanmamıştır.


Veya muhtemelen her bir değeri anahtar (lar) ına eşleyen ikinci bir sözlük.
DavidRR

@DavidRR yalnızca anahtarlar benzersiz olmalıdır, bu nedenle ikinci sözlük yaklaşımı gerçekten işe yaramaz. Ancak, bir değerin anahtarlarını almak için sözlükte dolaşabilirsiniz.
Maksimum Hodges

Bir sözlük için sorun çağrıları birden desteklemeye Eğer intbaşına değerler stringtuşu ardından Sözlük böyle tanımlanabilir: Dictionary<string, List<int>>.
DavidRR

şimdi bunu yinelemeden nasıl çift yönlü hale getirebilirim?
Maksimum Hodges

OP'ın sorusuna ilişkin olarak, standart Dictionaryyok değil çift yönlü bir kapasitesi sunmaktadır. Dolayısıyla, sahip olduğunuz her şey bir standartsa Dictionaryve belirli bir değerle ilişkili anahtar (lar) ı bulmak istiyorsanız, gerçekten yinelemelisiniz! Ancak, "büyük" sözlükler için yineleme düşük performansa neden olabilir. Kendi verdiğim cevabın yinelemeye (LINQ aracılığıyla) dayandığına dikkat edin. İlk Eğer Dictionarybaşka değişikliğe tabi olmayıp, bir ters inşa edebilirsiniz Dictionaryhız aramaları tersine çevirmek için bir kez.
DavidRR

1

Ters arama yapmak için LINQ kullanın Dictionary<K, V>. Ancak değerlerinizdeki Dictionary<K, V>değerlerin farklı olmayabileceğini unutmayın.

gösteri:

using System;
using System.Collections.Generic;
using System.Linq;

class ReverseDictionaryLookupDemo
{
    static void Main()
    {
        var dict = new Dictionary<int, string>();
        dict.Add(4, "Four");
        dict.Add(5, "Five");
        dict.Add(1, "One");
        dict.Add(11, "One"); // duplicate!
        dict.Add(3, "Three");
        dict.Add(2, "Two");
        dict.Add(44, "Four"); // duplicate!

        Console.WriteLine("\n== Enumerating Distinct Values ==");
        foreach (string value in dict.Values.Distinct())
        {
            string valueString =
                String.Join(", ", GetKeysFromValue(dict, value));

            Console.WriteLine("{0} => [{1}]", value, valueString);
        }
    }

    static List<int> GetKeysFromValue(Dictionary<int, string> dict, string value)
    {
        // Use LINQ to do a reverse dictionary lookup.
        // Returns a 'List<T>' to account for the possibility
        // of duplicate values.
        return
            (from item in dict
             where item.Value.Equals(value)
             select item.Key).ToList();
    }
}

Beklenen çıktı:

== Enumerating Distinct Values ==
Four => [4, 44]
Five => [5]
One => [1, 11]
Three => [3]
Two => [2]

1
Bununla ilgili gördüğüm sorun, ters yönü elde etmek için sözlükteki her öğeyi kontrol ediyor olmanızdır. Bir O (n) arama süresi, bir sözlük kullanma amacını ortadan kaldırır; O (1) olmalıdır.
stephen

@stephen - Kabul edildi. Başkalarının da belirttiği gibi, performans çok önemliyse, değerler için ayrı bir sözlük veya iki yönlü bir sözlük uygun olacaktır. Bununla birlikte, bir değer araması yapma ihtiyacı seyrekse ve bunu yaparken performans kabul edilebilirse, burada özetlediğim yaklaşım dikkate alınmaya değer olabilir. Bununla birlikte, cevabımda LINQ kullanımı, OP'nin .NET 2.0 ile kullanıma uygun bir çözüm arzusuyla uyumlu değildir. (Bir .NET 2.0 kısıtlaması muhtemelen 2014 yılında daha az olası olsa da)
DavidRR

1
Dictionary<string, string> dic = new Dictionary<string, string>();
dic["A"] = "Ahmed";
dic["B"] = "Boys";

foreach (string mk in dic.Keys)
{
    if(dic[mk] == "Ahmed")
    {
        Console.WriteLine("The key that contains \"Ahmed\" is " + mk);
    }
}

1
Cevap gönderdiğiniz için teşekkürler! Bir kod parçacığı soruyu yanıtlayabilirken, etrafa açıklama vb. Gibi bazı ek bilgiler eklemek yine de harika.
j0k

0

Anahtarların sözlükteki işaret değerleriyle ilişkilendirileceğini varsayarak kabul edilen cevabın ( https://stackoverflow.com/a/255638/986160 ) bir bükümü olarak . ( Https://stackoverflow.com/a/255630/986160 ) ile benzer ancak biraz daha zarif. Yenilik, tüketen sınıfın bir numaralandırma alternatifi olarak (ancak dizeler için de) kullanılabilmesi ve sözlüğün IEnumerable'ı kullanmasıdır.

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

namespace MyApp.Dictionaries
{

    class BiDictionary<TFirst, TSecond> : IEnumerable
    {
        IDictionary<TFirst, TSecond> firstToSecond = new Dictionary<TFirst, TSecond>();
        IDictionary<TSecond, TFirst> secondToFirst = new Dictionary<TSecond, TFirst>();

        public void Add(TFirst first, TSecond second)
        {
            firstToSecond.Add(first, second);
            secondToFirst.Add(second, first);
        }

        public TSecond this[TFirst first]
        {
            get { return GetByFirst(first); }
        }

        public TFirst this[TSecond second]
        {
            get { return GetBySecond(second); }
        }

        public TSecond GetByFirst(TFirst first)
        {
            return firstToSecond[first];
        }

        public TFirst GetBySecond(TSecond second)
        {
            return secondToFirst[second];
        }

        public IEnumerator GetEnumerator()
        {
            return GetFirstEnumerator();
        }

        public IEnumerator GetFirstEnumerator()
        {
            return firstToSecond.GetEnumerator();
        }

        public IEnumerator GetSecondEnumerator()
        {
            return secondToFirst.GetEnumerator();
        }
    }
}

Tüketen bir sınıf olarak sahip olabilirsiniz

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

namespace MyApp.Dictionaries
{
    class Greek
    {

        public static readonly string Alpha = "Alpha";
        public static readonly string Beta = "Beta";
        public static readonly string Gamma = "Gamma";
        public static readonly string Delta = "Delta";


        private static readonly BiDictionary<int, string> Dictionary = new BiDictionary<int, string>();


        static Greek() {
            Dictionary.Add(1, Alpha);
            Dictionary.Add(2, Beta);
            Dictionary.Add(3, Gamma);
            Dictionary.Add(4, Delta);
        }

        public static string getById(int id){
            return Dictionary.GetByFirst(id);
        }

        public static int getByValue(string value)
        {
            return Dictionary.GetBySecond(value);
        }

    }
}

1
Bu, temelde altı yıl önce gönderilen bir yanıtla aynıdır ve daha sonra belirtildiği gibi, anahtarlar tekli değerlerle ilişkilendirilmez. Her anahtarın birden çok değeri olabilir.
Dour Yüksek Arch

Eh biliyorum ama benim sürümüm IEnumerable uyguluyor ve daha zarif. Ayrıca tüketim sınıfı örneği BiDictionary sınıfını farklı bir kullanılabilirlik düzeyine koyuyor - C # tarafından sağlanmayan dizelerin ve kimliklerin statik numaralandırma sorununu çözüyor. Cevabımı okuduysanız da ona atıfta bulundum!
Michail Michailidis

0

O halde layman'ın çözümü

Böyle bir sözlük yapmak için aşağıdakine benzer bir işlev yazılabilir:

    public Dictionary<TValue, TKey> Invert(Dictionary<TKey, TValue> dict) {
    Dictionary<TValue, TKey> ret = new Dictionary<TValue, TKey>();
    foreach (var kvp in dict) {ret[kvp.value] = kvp.key;} return ret; }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.