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
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.
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.
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.
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
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)
How about using the linq function ToDictionary:
var reversedDictionary = dictionary.ToDictionary(x => x.Value, x => x.Key);