Case insensitive access for generic dictionary - c#

I have an application that use managed dlls. One of those dlls return a generic dictionary:
Dictionary<string, int> MyDictionary;
The dictionary contains keys with upper and lower case.
On another side I am getting a list of potential keys (string) however I cannot guarantee the case. I am trying to get the value in the dictionary using the keys. But of course the following will fail since I have a case mismatch:
bool Success = MyDictionary.TryGetValue( MyIndex, out TheValue );
I was hoping the TryGetValue would have an ignore case flag like mentioned in the MSDN doc, but it seems this is not valid for generic dictionaries.
Is there a way to get the value of that dictionary ignoring the key case?
Is there a better workaround than creating a new copy of the dictionary with the proper StringComparer.OrdinalIgnoreCase parameter?

There's no way to specify a StringComparer at the point where you try to get a value. If you think about it, "foo".GetHashCode() and "FOO".GetHashCode() are totally different so there's no reasonable way you could implement a case-insensitive get on a case-sensitive hash map.
You can, however, create a case-insensitive dictionary in the first place using:-
var comparer = StringComparer.OrdinalIgnoreCase;
var caseInsensitiveDictionary = new Dictionary<string, int>(comparer);
Or create a new case-insensitive dictionary with the contents of an existing case-sensitive dictionary (if you're sure there are no case collisions):-
var oldDictionary = ...;
var comparer = StringComparer.OrdinalIgnoreCase;
var newDictionary = new Dictionary<string, int>(oldDictionary, comparer);
This new dictionary then uses the GetHashCode() implementation on StringComparer.OrdinalIgnoreCase so comparer.GetHashCode("foo") and comparer.GetHashcode("FOO") give you the same value.
Alternately, if there are only a few elements in the dictionary, and/or you only need to lookup once or twice, you can treat the original dictionary as an IEnumerable<KeyValuePair<TKey, TValue>> and just iterate over it:-
var myKey = ...;
var myDictionary = ...;
var comparer = StringComparer.OrdinalIgnoreCase;
var value = myDictionary.FirstOrDefault(x => String.Equals(x.Key, myKey, comparer)).Value;
Or if you prefer, without the LINQ:-
var myKey = ...;
var myDictionary = ...;
var comparer = StringComparer.OrdinalIgnoreCase;
int? value;
foreach (var element in myDictionary)
{
if (String.Equals(element.Key, myKey, comparer))
{
value = element.Value;
break;
}
}
This saves you the cost of creating a new data structure, but in return the cost of a lookup is O(n) instead of O(1).

For you LINQers out there that never use a regular dictionary constructor
myCollection.ToDictionary(x => x.PartNumber, x => x.PartDescription, StringComparer.OrdinalIgnoreCase)

There is much simpler way:
using System;
using System.Collections.Generic;
....
var caseInsensitiveDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

Its not very elegant but in case you cant change the creation of dictionary, and all you need is a dirty hack, how about this:
var item = MyDictionary.Where(x => x.Key.ToLower() == MyIndex.ToLower()).FirstOrDefault();
if (item != null)
{
TheValue = item.Value;
}

Related

Order Dictionary from Keys from another Dictionary

I have two dictionaries:
Dictionary<string, Tuple<T, T>> dict1
Dictionary<Enum, Tuple<string, DateTime, DateTime>> dict2
The string value in the first item in the tuple is sometimes equal to the key in the first dictionary. I would like to sort the second dictionary by the enum value and then sort the first dictionary based on the order that dict2 has. How would I be able to do that while retaining the other keys that might be in dict1? I'm able to get as far as sorting the dictionary.
var positions = new Dictionary<Enum, string>();
//This foreach loop can be simplified by a linq expression.
foreach (var position in dict2)
{
var isFound = dict1.Any(x => x.Key == position.Value.Item1.Value);
if (isFound)
{
clubPositions.Add(position.Key, position.Value.Item1.Value);
}
}
var sortedPositions = positions.OrderByDescending(x => x.Key);
You are looking for the SortedDictionary documented on MSDN here. You will need to instantiate them as such:
var dict1 = new SortedDictionary<string, Tuple<DateTime, DateTime>>();
var dict2 = new SortedDictionary<Enum, Tuple<string, DateTime, DateTime>>();
Once you have the sorted dictionaries instances you can use LINQ to map or filter or do whatever else is desired on them. When items are added to the dictionaries they are automatically sorted based on either the ICompare<T> for the given TKey (or the default IComparer if not explicitly provided).
One downside is the fact that this sorts based on the key alone, there is no concept of sorting based on values.
The way I understand the question is not to sort the first dictionary, but to be able to iterate its elements in order defined by the second dictionary keys. If that's correct, the following should do the trick:
var orderedKeys = new HashSet<string>(dict2.OrderBy(e => e.Key).Select(e => e.Value.Item1));
var orderedEntries = orderedKeys.Where(dict1.ContainsKey)
.Select(key => new KeyValuePair<string, Tuple<T, T>>(key, dict1[key]))
.Concat(dict1.Where(e => !orderedKeys.Contains(e.Key)));
Note that it will put the entries that has no corresponding key last in the order.
You can not sort dictionary as it uses hash algorithm for constant search.
A regular dictionary cannot be sorted. You could use a SortedDictionary, it exists for this exact purpose.

Check key / value pair in List

I have list declared as
List<KeyValuePair<string, Int64>> KPList = new List<KeyValuePair<string, long>>();
I need to check if a combination of key and value already exists. I can't use dictionary since I need to have unique combination of key and value where in case a key will have multiple values but as a single pair
if(!KPList.Any(p=> p.Key ==keyp && p.Value == valuep))
What is wrong in this?
You can also use HashSet, which doesn't have values, but works as you need.
HashSet< Tuple<string, long> > KPSet = new HashSet< Tuple<string, long> >();
...
if(KPSet.Contains(p))
{
...
}
For easy-use and best performance I would like to suggest use combination of Dictionary and HashSet :
var KPDict = new Dictionary<string, HashSet<long>>();
Then it will provides you O(1)+O(1) lookup complexity and easy check of value:
if (KPDict.ContainsKey(keyp) && KPDict[keyp].Contains(valuep)) {
//do some actions
}
else{
//some logic in case keyp, valuep pair not found in KPDict
}

How to convert Dictionary<> to Hashtable in C#?

I see many question/answers about how to convert a Hashtable to a Dictionary, but how can I convert a Dictionary to a Hashtable?
The easiest way is using constructor of Hashtable:
var dictionary = new Dictionary<object, object>();
//... fill the dictionary
var hashtable = new Hashtable(dictionary);
Dictionary<int, string> dictionary = new Dictionary<int, string>
{
{1,"One"},
{2,"Two"}
};
Hashtable hashtable = new Hashtable(dictionary);
Try this
Seems pretty rare to want to do, but at the simplest:
var hash = new Hashtable();
foreach(var pair in dictionary) {
hash.Add(pair.Key,pair.Value);
}
(assuming no unusual "implements typed equality check but not untyped equality check" etc)
You might want to consider using the Hashtable constructor overload that takes an IEqualityComparer parameter:
var hashtable = new Hashtable(dictionary, (IEqualityComparer) dictionary.Comparer);
In this way, your Hashtable uses the same Comparer as the dictionary. For example, if your dictionary used a case-insensitive string key, you might want your Hashtable to be case-insensitive too. E.g.:
var d = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
d.Add("a", "a");
d.Add("b", "b");
bool found;
found = d.ContainsKey("A"); // true
var hashtable1 = new Hashtable(d);
var hashtable2 = new Hashtable(d, (IEqualityComparer) d.Comparer);
found = hashtable1["A"] != null; // false - by default it's case-sensitive
found = hashtable2["A"] != null; // true - uses same comparer as the original dictionary

Get Value from key using linq

I have Dictionary from string key i want to get Value of corresponding key using Linq
Why do you want to get a value from a Dictionary using LINQ? You can just get the value using:
int value = dictionary[key];
You could use Single, but it's totally pointless and more code:
var keyValuePair = dictionary.Single(x => x.Key == key);
int value = keyValuePair.Value;
Why use Linq for something that is built in?
var val = myDict[key];
Use Linq where it makes sense (querying collections), not for something that is already well handled by the Dictionary classes.
returns the string value in this particular instance.
Disctionary<int, string> CustomValues = new Dictionary<int, string>();
CustomValues[int]; //CustomValues[key];
To Get the Value from the Dictionary Key
Dictionary<int,string>dict=new Dictionary<int,string>();
dict.Add(1,"Maha");
dict.Add(2,"Malathi");
dict.Add(3,"Mithra");
dict.Add(4,"Saravana");
var val=dict.Where(x=>x.Key==key).Select(x=>x.Value);//get the value from dictionary where key=3
(or)
var val=dict[Key];//get the value for Dictionary key 3.
Output: Mithra

How do I select a List from something like new Dictionary(int, List<Customer>);

Dictionary<int, List<Customer>> dictionary = new Dictionary<int, List<Customer>>();
I want to query based on the key and get a List back. Not sure how to structure the LINQ query for that.
Desired Output:
A List<Customer> for a particular key in the Dictionary.
That's what the Dictionary (as you've defined the generic arguments) will do. So, dictionary[key] will return the list. Note that it will throw an exception if you haven't initialized it already with dictionary[key] = new List<Customer>();.
You don't need to use LINQ for this, but if you really want to
int key = 1;
List<Customer> customers = dictionary.Single(item => item.Key == key).Value;
The simplest way is to just retrieve the value for the key using the regular [] operator
dictionary[key];

Categories