일반 사전의 지정된 값의 여러 키를 얻습니까?


122

.NET 일반 사전에서 키 값을 가져 오는 것은 쉽습니다.

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

그러나 값이 주어진 키를 가져 오는 것은 여러 키가있을 수 있기 때문에 간단하지 않습니다.

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

1
int[]단일 값을 예상 할 때 반환 유형이 왜 입니까?
anar khalilov 2014 년

3
@Anar, Domenic에 대한 내 대답을 읽으십시오. "중복 된 값은 거의 없지만 불가능하지는 않습니다."
Dour High Arch

가치의 열쇠? 난 당신이 말은 생각 의 키를
최대 스

답변:


144

좋습니다. 다음은 다중 양방향 버전입니다.

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에서 읽은 내용에서 이것은 BiDictionary 대신 BiLookup이어야하지 않습니까? 그것이 중요하거나 아무것도 아니라는 것이 아니라, 내가 여기서 올바르게 이해하는지 궁금합니다.
Svish

또한 GetByFirst를 사용하고 EmptySecondList를 다시 가져 와서 몇 가지를 추가 한 다음 GetByFirst를 다시 호출했습니다. 그러면 빈 목록이 아닌 몇 가지 항목이 포함 된 목록이 표시되지 않습니까?
Svish 2009-08-04

@Svish : 아니요, 목록에 추가하려고하면 예외가 발생하기 때문입니다 (배열에 추가 할 수 없음). 그리고 예, BiLookup이 아마도 더 나은 이름이 될 것입니다.
Jon Skeet

이것이 OP의 질문에 대한 답변을 보는 동안 이것은 다소 순진한 구현이 아닙니까? 더 현실적인 구현은 Dictionary <> List <> Dictionary가 아니므로 실제로 두 개의 다른 키로 풍부한 개체를 찾을 수 있습니까?
Chris Marisic

@ChrisMarisic : 무슨 뜻인지 잘 모르겠습니다.하지만 이와 같은 것은 제가 꽤 많이 사용했고 더 이상 필요하지 않은 것입니다.
Jon Skeet

74

다른 모든 사람들이 말했듯이 사전 내에 값에서 키로의 매핑이 없습니다.

방금 값에서 여러 키로 매핑하기를 원했습니다. 단일 값 버전의 경우이 솔루션을 여기에 남겨두고 다중 항목 양방향지도에 대한 또 다른 답변을 추가하겠습니다.

여기서 취하는 일반적인 접근 방식은 두 개의 사전을 갖는 것입니다. 하나는 한 방향으로 매핑되고 다른 하나는 다른 방향으로 매핑됩니다. 그것들을 별도의 클래스로 캡슐화하고 중복 키 또는 값이있을 때 원하는 작업을 수행합니다 (예 : 예외 발생, 기존 항목 덮어 쓰기 또는 새 항목 무시). 개인적으로 저는 아마도 예외를 던질 것입니다. 성공 동작을 더 쉽게 정의 할 수 있습니다. 이 같은:

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
구체적인 클래스에서 파생시킬 이유가 없다고 생각합니다.-저는 매우 신중한 생각 없이는 상속을 좋아하지 않습니다.하지만 확실히 IEnumerable 등을 구현할 수 있습니다. 실제로 IDictionary <TFirst, TSecond> 및 IDictionary를 구현할 수 있습니다. <TSecond, TFirst>.
Jon Skeet

1
(TFirst와 TSecond가 같으면 상당히 이상 할 수 있지만 ...)
Jon Skeet

6
실제로 IDictionary <TFirst, TSecond> 및 IDictionary <TSecond, TFirst>를 동시에 구현할 수 없습니다. .NET 4.0에서는이를 허용하지 않습니다
Sebastian

2
@nawfal : 사전 호출 중 하나Add 가 실패하지만 두 번째 호출이면 시스템이 혼란스러워집니다. 내 방식으로 예외 후에도 여전히 일관된 컬렉션이 있습니다.
Jon Skeet 2013 년

1
@nawfal : 글쎄, 내가 먼저 ... 내가 추측하고있어 답을 쓸 때 내가 왜 그랬는지 그건 여부를 알 수는 없습니다)
존 소총

26

키의 고유성은 보장되지만 값의 고유성은 그렇지 않기 때문에 사전은 실제로 이와 같이 작동하도록되어 있지 않습니다. 예를 들어

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

당신은 무엇을 얻기를 기대 greek.WhatDoIPutHere("Alpha")합니까?

따라서 이와 같은 것이 프레임 워크로 롤링 될 것으로 기대할 수 없습니다. 고유 한 용도를위한 고유 한 방법이 필요합니다 .-- 배열 (또는 IEnumerable<T>) 을 반환 하시겠습니까? 주어진 값을 가진 여러 키가있는 경우 예외를 던지고 싶습니까? 아무것도 없으면 어떨까요?

개인적으로 나는 다음과 같이 열거 형으로 갈 것입니다.

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();

우아한 솔루션이지만 2.0에서 작동해야합니다. 중복 값은 거의 발생하지 않지만 불가능하지는 않으며 컬렉션을 반환하는 것이 더 좋습니다.
Dour High Arch

23

Linq없이이를 수행하는 가장 쉬운 방법은 쌍을 반복하는 것입니다.

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

Linq가 있다면 다음과 같이 쉽게 할 수 있습니다.

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

dour,하지만 위의 var 유형이 있습니까?! 확실히 당신은 3.0에 있습니까? 아래의 내 업데이트도 참조하십시오.
비둘기

죄송합니다. 단순히 타이핑을 줄이기 위해 "var"를 사용했습니다. 선형 검색을 선호하지 않습니다. 사전이 클 수 있습니다.
Dour High Arch

2
var프레임 워크 기능이 아니라 언어 기능입니다. C # -6.0에서 null-coalescing을 사용 하고 원하는 경우 CF-2.0을 대상으로 지정할 수 있습니다.
binki

3

사전은 값의 해시를 유지하지 않고 키만 유지하므로 값을 사용하여 검색하는 데 최소한 선형 시간이 걸립니다. 가장 좋은 방법은 단순히 사전의 요소를 반복하고 일치하는 키를 추적하거나 다른 데이터 구조로 전환하는 것입니다. 아마도 두 개의 사전 매핑 key-> value 및 value-> List_of_keys를 유지하는 것입니다. 후자를 수행하면 검색 속도를 위해 스토리지를 교환하게됩니다. @Cybis 예제를 이러한 데이터 구조로 바꾸는 데 많은 시간이 걸리지 않습니다.


3

완전한 양방향 사전 (지도뿐만 아니라)을 원했기 때문에 누락 된 기능을 추가하여 IDictionary 호환 클래스로 만들었습니다. 이것은 고유 한 키-값 쌍이있는 버전을 기반으로합니다. 원하는 경우 다음 파일이 있습니다 (대부분의 작업은 XMLDoc이었습니다).

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

개정 : 사전이 아닌 다른 것이 필요하다는 것을 발견하면 사전이 단방향 키이기 때문에 괜찮습니다. 즉, 값이 고유하지 않을 수 있습니다.

그것은 당신이 c # 3.0을 사용하는 것처럼 보이기 때문에 루핑에 의지 할 필요가 없으며 다음과 같은 것을 사용할 수 있습니다.

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

사전에 .FindByValue가 없습니다. 값을 반복하는 것보다 다른 데이터 구조로 이동하는 것이 좋습니다.
Dour High Arch

2

사전 클래스는이 경우에 최적화되어 있지 않지만 C # 2.0에서 실제로 수행하려면 다음을 수행 할 수 있습니다.

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

우아함을 위해 LINQ 솔루션을 선호하지만 이것이 2.0 방식입니다.


1

그 기능을 가진 Dictionary의 하위 클래스를 만들 수 없습니까?


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

편집 : 죄송합니다, 코드를 처음으로받지 못했습니다.


그것은 단지 내가 키에 사용하는 것을 전환하고 문자열 키의 int 값만 반환 할뿐입니다. 두 가지 방법을 모두 사용해야합니다. 그리고 Domenic이 지적했듯이 중복 문자열 값을 가질 수 있습니다.
Dour High Arch

int 키에 대해 중복 된 문자열 값을 가질 수있는 경우 문자열로 조회 할 때 무엇을 얻을 것으로 예상합니까? 해당하는 정수의 목록 객체?
Cybis

1

여기에서 제안 된 "간단한"양방향 사전 솔루션은 복잡하며 이해, 유지 또는 확장하기 어려울 수 있습니다. 또한 원래 질문은 "값에 대한 키"를 요청했지만 분명히 여러 키가있을 수 있습니다 (이후 질문을 편집했습니다). 전체 접근 방식은 다소 의심 스럽습니다.

소프트웨어 변경. 유지하기 쉬운 코드를 작성하는 것은 다른 "영리한"복잡한 해결 방법에 우선 순위를 부여해야합니다. 사전의 값에서 키를 다시 가져 오는 방법은 반복하는 것입니다. 사전은 양방향으로 설계되지 않았습니다.


또는 각 값을 해당 키에 매핑하는 두 번째 사전 일 수도 있습니다.
DavidRR

@DavidRR 전용 키는 고유해야하므로 두 번째 사전 접근 방식은 실제로 작동하지 않습니다. 그러나 값에 대한 키를 얻기 위해 사전을 간단히 반복 할 수 있습니다.
Max Hodges

문제가 사전에 키당 여러 int값 을 지원해야하는 경우 사전을 string다음과 같이 정의 할 수 있습니다 Dictionary<string, List<int>>..
DavidRR

이제 반복하지 않고 어떻게 양방향으로 만들 수 있습니까?
Max Hodges

OP의 질문과 관련하여 표준 Dictionary은 양방향 기능을 제공 하지 않습니다 . 따라서 가지고있는 모든 것이 표준 Dictionary이고 특정 값과 관련된 키를 찾으려면 실제로 반복해야합니다! 그러나 "대형"사전의 경우 반복하면 성능이 저하 될 수 있습니다. 참고 대답 나 자신이 제공하는 것으로는 (LINQ를 통해) 반복을 기반으로합니다. 이니셜 Dictionary이 더 이상 변경되지 않는 경우 Dictionary역방향 조회 속도를 높이기 위해 역방향을 한 번 빌드 할 수 있습니다 .
DavidRR

1

LINQ 를 사용 하여 역방향 Dictionary<K, V>조회 를 수행합니다 . 그러나 가치의 Dictionary<K, V>가치는 구별되지 않을 수 있음 을 명심하십시오 .

데모:

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

예상 출력 :

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

1
내가 보는 문제는 역방향을 얻기 위해 사전의 모든 요소를 ​​확인하고 있다는 것입니다. O (n) 검색 시간은 사전 사용 목적을 무효화합니다. O (1)이어야합니다.
stephen

@stephen-동의합니다. 다른 사람들이 지적했듯이 성능이 가장 중요하다면 값에 대한 별도의 사전 또는 양방향 사전 이 적절할 것입니다. 그러나 값 조회를 수행해야하는 필요성이 드물고 수행하는 성능이 허용되는 경우 여기에서 설명하는 접근 방식을 고려할 가치가 있습니다. 즉, 내 대답에서 LINQ를 사용하는 것은 .NET 2.0과 함께 사용하기에 적합한 솔루션에 대한 OP의 욕구와 호환되지 않습니다. (닷넷 2.0 제약은 2014 년에 틀림없이 적은 가능성이지만)
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
답변을 게시 해 주셔서 감사합니다! 코드 스 니펫이 질문에 답할 수 있지만 Explain 등과 같은 추가 정보를 추가하는 것은 여전히 ​​좋습니다.
j0k

0

키가 사전의 부호 값과 연결된다는 가정하에 허용 된 답변 ( https://stackoverflow.com/a/255638/986160 ) 의 왜곡으로 . ( https://stackoverflow.com/a/255630/986160 )과 비슷하지만 조금 더 우아합니다. 참신한 점은 소비하는 클래스를 열거 형 대안으로 사용할 수 있고 (문자열에 대해서도) 사전이 IEnumerable을 구현한다는 것입니다.

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

그리고 소비 클래스로서 당신은

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
이것은 기본적으로 6 년 전에 게시 된 답변 과 동일하며 당시 언급했듯이 키는 단일 값과 관련이 없습니다. 각 키는 여러 값을 가질 수 있습니다.
Dour High Arch

잘 알지만 내 버전은 IEnumerable을 구현하고 더 우아합니다. 또한 소비 클래스 예제는 BiDictionary 클래스를 다른 수준의 사용성에 배치합니다. C #에서 제공하지 않는 문자열 및 ID의 정적 열거 문제를 해결합니다. 내 대답을 읽으면 나는 또한 그것을 참조했습니다!
Michail Michailidis 2014

0

그런 다음 평신도의 솔루션

이러한 사전을 만들기 위해 아래와 비슷한 함수를 작성할 수 있습니다.

    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; }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.