değere göre sözlük anahtarı al


361

Sözlük anahtarını C # değerine göre nasıl alabilirim?

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

Böyle bir şey istiyorum:

getByValueKey(string value);

getByValueKey("one")iade edilmelidir "1".

Bunu yapmanın en iyi yolu nedir? Belki HashTable, Sıralama Listeleri?



daha önce bu makaleyi okudum, ama cevap oraya.
loviji

5
Evet, ama orada Skeet'ten kabul edilmiş bir cevap alıyorsunuz .
14'te

7
Burada kabul edilen cevap, yinelenen sorudaki her şeyden büyük ölçüde daha iyidir. Ancak bu soru daha eskidir; Jon cevap verdiğinde belki lambda ifadeleri yoktu.
Seth Battin

5
Bu soru, diğeri özellikle .Net 2.0'ı ele aldığından yeniden açıldığında, bu .Net çerçevesinin mevcut sürümü için daha iyi bir cevaba sahip değildir ve daha iyi bir cevabı vardır.
Rachel

Yanıtlar:


645

Değerlerin mutlaka benzersiz olması gerekmez, bu nedenle bir arama yapmanız gerekir. Bunun gibi bir şey yapabilirsiniz:

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

Değerler benzersizse ve okunandan daha az sıklıkta eklenmişse, değerlerin anahtar ve anahtarların değer olduğu ters bir sözlük oluşturun.


3
@loviji: Döngüsel çözümde, değerin sözlüğün sonunda olması durumunda, onu bulmak için diğer tüm değerlerin üzerinden geçmesi gerektiğini unutmayın. Çok sayıda girişiniz varsa, programınız yavaşlar.
Zach Johnson

2
@Zach Johnson: Teşekkürler. Size katılıyorum. ve cevabını ben de seviyorum. ama sözlükte 8-10 giriş var. ve dinamik olarak eklenmezler. ve bence, bu cevabı kullanmak fena değil.
loviji

4
Burada bir şey mi eksik? Yukarıdaki kod, anahtarı değil, değeri döndürür. Types.FirstOrDefault (x => x.Value == "one") olmaz. Anahtar daha uygun mu?
floele

19
Herkese uyarı, FirstOrDefault herhangi bir eşleşme bulamaz ve boş nesnede "Anahtar" a erişmeye çalışırsa, düzenlemelerle birlikte kabul edilen cevap bir istisna atar.
Jim Yarbro

11
@JimYarbro: çünkü KeyValuePair<Tkey,Tvalue>bir yapı, yani bir değer türü, asla olamaz null. FirstOrDefaulttüm alanların varsayılan değerleriyle başlatıldığı bir örnek döndürür ( nulldizeler gibi veya ints için 0). Yani bir istisna alamazsınız. Ancak bir değer bulup bulamadığınızı da bilmiyorsunuz, bu nedenle bu cevap, değerin mevcut olmadığı durumunu kapsamıyor.
Tim Schmelter

26

Bunu yapabilirsin:

  1. KeyValuePair<TKey, TValue>Sözlükteki tüm 'ler arasında dolaşarak (sözlükte bir takım girişleriniz varsa büyük bir performans isabeti olacaktır)
  2. Biri değer-anahtar eşleme ve diğeri anahtar-değer eşleme (bellekte iki kat daha fazla yer kaplayan) için olmak üzere iki sözlük kullanın.

Performans dikkate alınmıyorsa Yöntem 1'i kullanın, bellek dikkate alınmıyorsa Yöntem 2'yi kullanın.

Ayrıca, tüm anahtarların benzersiz olması gerekir, ancak değerlerin benzersiz olması gerekmez. Belirtilen değere sahip birden fazla anahtarınız olabilir.

Anahtar / değer ilişkisini tersine çevirememenizin bir nedeni var mı?


1
Ters sözlüğü programlı olarak oluşturmak için hala yöntem 1'i kullanmamız gerekir, değil mi?
Kyle Delaney

Bu yaygın bir olay ise, o zaman bu takası da tavsiye ederim (son sorunuzla ilgili).
Bonez024

3

Linq bağlanmasının mevcut olmadığı ve lambda'yı açıkça genişletmek zorunda kaldığım bir durumdaydım. Basit bir fonksiyonla sonuçlandı:

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;
}

Aşağıdaki gibi çağırın:

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 ve diğer sınırlı ortamlarda çalışır.


Bir uzatma yöntemi olarak eklemek daha güzel :-)
Chayim Friedman

-1

belki böyle bir şey:

foreach (var keyvaluepair in dict)
{
    if(Object.ReferenceEquals(keyvaluepair.Value, searchedObject))
    {
        //dict.Remove(keyvaluepair.Key);
        break;
    }
}

-1

Bir çift arama sınıfı oluşturduk:

/// <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 (), sözlük değerlerinizi bir nesne listesine dönüştürür. IndexOf ("one") yeni Listenizde "one" ifadesini arar ve sözlükteki Anahtar / Değer çiftinin diziniyle eşleşen Dizini döndürür.

Bu yöntem sözlük tuşlarını umursamaz, sadece aradığınız değerin dizinini döndürür.

Sözlüğünüzde birden fazla "bir" değer olabileceğini unutmayın. Ve "anahtar al" yöntemi olmamasının nedeni de budur.


-4

Aşağıdaki Kod yalnızca Benzersiz Değer Verileri içeriyorsa çalışır

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 Kimi'nin en büyük cevabından daha kötü bir performans için çok fazla kod (sizinkinden 6 yıl önce yayınlanan). Bu 2 listeyi oluşturmak için Anahtarlar ve Değerler özelliklerinin öngörülmesine gerek yoktur (Linq's ToList bunu sizin için yapar). Ayrıca, IndexOf kullanacaksanız, ContainsValue çağrısından kaçınabilirsiniz (böylece aynı görev için tüm unsurlara rağmen 2 döngüden kaçınırsınız).
Mariano Desanze

2
Bu önerinin performansı sadece korkunç. İki sözlükten oluşan genel bir sınıf da oluşturabilirsiniz. Bunlardan biri Anahtar1 ve Anahtar2'yi, diğeri Anahtar2 ve Anahtar1'i içerir. Bu şekilde, her iki tuşu da ... cevabınızın önerdiği her şeyi olmadan alabilirsiniz.
Krythic

-11

Bunu yapmanın çok basit bir yolu var. Benim için mükemmel çalıştı.

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
Üzgünüz, ama cevabınız soruyu karşılamıyor. Soru, anahtarın değere göre nasıl bulunacağıyla ilgiliydi, cevabınız standardı gösteriyor: anahtarı anahtarla bulmak
Breeze

1
İlk seferinde görevi okuyun
Tommix

4
Ve bu, bayanlar ve baylar, tam olarak bir cevap göndermeden önce soruları okuduğumuz neden.
Krythic
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.