값으로 사전 키 가져 오기


361

C #에서 값으로 사전 키를 어떻게 얻습니까?

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

나는 이런 것을 원한다.

getByValueKey(string value);

getByValueKey("one")반환해야합니다 "1".

가장 좋은 방법은 무엇입니까? 아마도 HashTable, SortedLists입니까?


9
정확한 복제품 : stackoverflow.com/questions/255341
Gabe

나는이 기사를 전에 읽었지만 대답은 거기에 도착한다.
loviji

5
예, 그러나 Skeet으로부터 답변 을 얻 습니다 .
ruffin

7
여기에서 받아 들여진 대답은 중복 질문의 모든 것보다 훨씬 낫습니다. 그러나 그 질문은 더 오래되었습니다. Jon이 대답했을 때 람다식이 없었을 것입니다.
Seth Battin

5
다른 질문은 .Net 2.0을 구체적으로 다루기 때문에이 질문을 다시 열면이 질문은 현재 버전의 .Net 프레임 워크에 대해 더 나은 대답을 얻지 못합니다.
Rachel

답변:


645

값이 반드시 고유하지 않아도되므로 조회를 수행해야합니다. 다음과 같이 할 수 있습니다 :

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

값이 고유하고 읽기보다 덜 자주 삽입되는 경우 값이 키이고 키가 값인 역 사전을 작성하십시오.


3
@loviji : 루핑 솔루션에서 값이 사전의 끝에있는 경우 다른 모든 값을 찾아서 찾아야합니다. 많은 항목이 있으면 프로그램 속도가 느려집니다.
Zach Johnson

2
@Zach Johnson : 감사합니다. 나는 당신에 동의합니다. 그리고 당신의 대답도 좋아합니다. 내 사전에는 8-10 개의 항목이 있습니다. 동적으로 추가되지 않습니다. 그리고 나는이 대답을 사용하는 것이 나쁜 해결책이 아니라고 생각합니다.
loviji

4
여기에 뭔가 빠졌습니까? 위의 코드는 키가 아닌 값을 반환합니다. Types.FirstOrDefault (x => x.Value == "one"). 키가 더 적합합니까?
floele

19
모두에게 경고합니다. FirstOrDefault가 일치하는 항목을 찾지 못하면 null 객체에서 "Key"에 액세스하려고 시도하면 편집이 허용되는 승인 된 응답에서 예외가 발생합니다.
Jim Yarbro

11
@ Jimimarbro : KeyValuePair<Tkey,Tvalue>구조체이므로 값 유형이므로 결코 될 수 없습니다 null. FirstOrDefault모든 필드가 기본값으로 초기화 된 인스턴스를 반환합니다 ( null문자열의 경우 또는 정수의 경우 0). 따라서 예외는 없습니다. 그러나 값을 찾았는지 여부도 알 수 없으므로이 답변은 값이 존재하지 않는 경우를 다루지 않습니다.
Tim Schmelter

26

당신은 그렇게 할 수 있습니다 :

  1. KeyValuePair<TKey, TValue>사전의 모든를 반복 하여 (사전에 많은 항목이있는 경우 상당한 성능 저하)
  2. 하나의 값 대 키 맵핑과 하나의 키 대 값 맵핑 (메모리에서 두 배의 공간을 차지함)에 대해 두 개의 사전을 사용하십시오.

성능을 고려하지 않으면 방법 1을 사용하고 메모리를 고려하지 않으면 방법 2를 사용하십시오.

또한 모든 키는 고유해야하지만 값이 고유하지 않아도됩니다. 지정된 값을 가진 둘 이상의 키가있을 수 있습니다.

키-값 관계를 되돌릴 수없는 이유가 있습니까?


1
프로그래밍 방식으로 역 사전을 만들려면 여전히 방법 1을 사용해야합니까?
Kyle Delaney

이것이 흔한 일이라면 마지막 질문과 관련 하여이 스왑도 권장합니다.
Bonez024

3

Linq 바인딩을 사용할 수없고 람다를 명시 적으로 확장해야하는 상황에있었습니다. 다음과 같은 간단한 기능을 수행했습니다.

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 및 기타 제한된 환경에서 작동합니다.


확장 방법으로 추가하는 것이 더 좋습니다 :-)
Chayim Friedman

-1

아마도 이런 식으로 :

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

-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 ( "one")은 "one"을 찾기 위해 새 List를 검색하고 사전의 키 / 값 쌍의 색인과 일치하는 색인을 반환합니다.

이 방법은 사전 키를 신경 쓰지 않고 찾고자하는 값의 인덱스를 반환합니다.

사전에 하나 이상의 "하나"값이있을 수 있습니다. 이것이 바로 "get key"방법이없는 이유입니다.


-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 Kimi (6 년 전에 게시 된) 의 최고 답변 보다 최악의 성능에 대한 코드가 너무 많습니다 . 이 두 목록을 만들기 위해 Keys and Values ​​속성을 지정할 필요는 없습니다 (Linq의 ToList가이를 수행함). 또한 IndexOf를 사용하려는 경우 ContainsValue에 대한 호출을 피할 수 있습니다 (따라서 동일한 작업의 모든 요소를 ​​통해 2 루프를 피함).
Mariano Desanze

2
이 제안의 성능은 끔찍합니다. 두 개의 사전으로 일반 클래스를 만들 수도 있습니다. 하나는 Key1과 Key2를 보유하고 다른 하나는 Key2와 Key1을 보유합니다. 이런 식으로 당신은 ... 잘 ... 당신의 대답이 제안한 모든 것없이 키를 얻을 수 있습니다.
Krythic

-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
죄송합니다. 답변이 질문에 맞지 않습니다. 문제는 가치로 열쇠를 찾는 방법에 관한 것이 었습니다. 답은 표준을 보여줍니다. 열쇠로 가치를 찾는 것
Breeze

1
다음에
Questiion을

4
신사 숙녀 여러분, 이것이 우리가 답을 게시하기 전에 질문을 읽는 이유입니다.
Krythic
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.