how to do a dictionary reverse lookup

前端 未结 5 1526
悲哀的现实
悲哀的现实 2021-02-05 04:23

I have a dictionary of type and for a particular case, I need to do a reverse lookup. So for instance suppose I have this entry <\"S

相关标签:
5条回答
  • 2021-02-05 05:01

    When the actual look-up direction of the dictionary (key > value) isn't of interest you can construct it in the other direction from the scratch. In addition, an extension method for IDictionary (Of TKey, TValue) is helpful, which makes it easier to capture multiple keys for one value.

    An example

    The problem: In a set of time units each of them could be given different names e. g., "h", "hr", "hrs", "hour", or "hours" for the time unit "hour" and I've got to find the fitting time unit for a name or abbreviation.

    My solution: (it's VB.net, but it should be easy to convert)

    Imports System
    Imports System.Collections.Generic
    Imports System.Runtime.CompilerServices
    
    Public Class TimeUnit
    
        Private ReadOnly _name As String
    
        Public Sub New(ByVal name As String, ByVal avgSpan As TimeSpan)
            _name = name
            _AvgSpan = avgSpan
        End Sub
    
        Public ReadOnly Property AvgSpan() As TimeSpan
    
        Public Overrides Function ToString() As String
            Return _name
        End Function
    
    End Class
    
    Public Class TimeUnits
    
        Private ReadOnly _items As New Dictionary(Of String, TimeUnit)(37, StringComparer.OrdinalIgnoreCase) _
            From {{{"n", "min", "minute", "minutes", "minuten"},
                   New TimeUnit("Minute", TimeSpan.FromMinutes(1))},
                  {{"h", "hr", "hrs", "std", "stunde", "hour", "stunden", "hours"},
                   New TimeUnit("Hour", TimeSpan.FromHours(1))},
                  {{"d", "t", "day", "tag", "days", "tage"},
                   New TimeUnit("Day", TimeSpan.FromDays(1))},
                  {{"m", "mo", "month", "monat", "months", "monate"},
                   New TimeUnit("Month", TimeSpan.FromDays(30.4375))},
                  {{"q", "quarter", "quartal", "quarters", "quartale"},
                   New TimeUnit("Quarter", TimeSpan.FromDays(91.3125))},
                  {{"y", "yy", "yyy", "yyyy", "j", "year", "jahr", "years", "jahre"},
                   New TimeUnit("Year", TimeSpan.FromDays(365.25))}}
    
        Public Function GetByAbbreviation(ByVal abbreviation As String) As TimeUnit
            Return _items(abbreviation)
        End Function
    
    End Class
    
    Public Module ExtensionMethods
        <Extension>
        Public Sub Add(Of TKey, TValue)(ByVal valItems As IDictionary(Of TKey, TValue), ByVal valKeys As IEnumerable(Of TKey), ByVal valValue As TValue)
            For Each tempKey As TKey In valKeys
                valItems.Add(tempKey, valValue)
            Next
        End Sub
    End Module
    
    Public Module Main
        Public Sub Main()
            Dim name As String = "Jahr"
            Console.WriteLine(String.Format("The time unit for '{0}' is {1}.", name, (New TimeUnits).GetByAbbreviation(name)))
        End Sub
    End Module
    

    output: The time unit for 'Jahr' is Year.

    0 讨论(0)
  • 2021-02-05 05:03

    Basically, You can use LINQ and get the Key like this, without reversing anything:

    var key = dictionary.FirstOrDefault(x => x.Value == "ab").Key;
    

    If you really want to reverse your Dictionary, you can use an extension method like this:

    public static Dictionary<TValue, TKey> Reverse<TKey, TValue>(this IDictionary<TKey, TValue> source)
    {
         var dictionary = new Dictionary<TValue, TKey>();
         foreach (var entry in source)
         {
             if(!dictionary.ContainsKey(entry.Value))
                 dictionary.Add(entry.Value, entry.Key);
         }
         return dictionary;
    } 
    

    Then you can use it like this:

    var reversedDictionary = dictionary.Reverse();
    var key = reversedDictionary["ab"];
    

    Note: if you have duplicate values then this method will add the first Value and ignore the others.

    0 讨论(0)
  • 2021-02-05 05:14

    Use the Linq ToDictionary function:

    var reversed = d.ToDictionary(x => x.Value, x => x.Key);
    

    You can see below that it works, as tested in Linqpad:

    var d = new Dictionary<int, string>();
    d.Add(1,"one");
    d.Add(2,"two");
    d.Dump(); //prints it out in linq-pad
    var reversed = d.ToDictionary(x => x.Value, x => x.Key);
    reversed.Dump(); //prints it out in linq-pad
    

    0 讨论(0)
  • 2021-02-05 05:15

    1) Keys are unique, values are not. For a given value you have a set of keys.

    2) Lookup by key is O(log n). Iterating with foreach or LINQ is O(n).

    So,
    Option A: Iterate with LINQ, spend O(n) per request, no additional memory.
    Option B: Maintain Dictionary<ValueType, HashSet<KeyType>>, spend O(log n) per request, use O(n) additional memory. (There are two suboptions: build this dictionary before a series of look-ups; maintain it all the time)

    0 讨论(0)
  • 2021-02-05 05:20

    How about using the linq function ToDictionary:

    var reversedDictionary = dictionary.ToDictionary(x => x.Value, x => x.Key);
    
    0 讨论(0)
提交回复
热议问题