I've got a Method that gets a IDictionary as a parameter.
Now I want to provide a method that retrieves the value from this dictionary, but it should be case-invariant.
So my solution to this right now was to have a static function that loops through the keys and converts them toLower() like this:
private static IDictionary<ILanguage, IDictionary<string, string>> ConvertKeysToLowerCase(
IDictionary<ILanguage, IDictionary<string, string>> dictionaries)
{
IDictionary<ILanguage, IDictionary<string, string>> resultingConvertedDictionaries
= new Dictionary<ILanguage, IDictionary<string, string>>();
foreach(ILanguage keyLanguage in dictionaries.Keys)
{
IDictionary<string, string> convertedDictionatry = new Dictionary<string, string>();
foreach(string key in dictionaries[keyLanguage].Keys)
{
convertedDictionatry.Add(key.ToLower(), dictionaries[keyLanguage][key]);
}
resultingConvertedDictionaries.Add(keyLanguage, convertedDictionatry);
}
return resultingConvertedDictionaries;
}
Now, this is ok, but still it's a pretty huge chunk of code that contradicts my idea of "clean and efficient". Do you know any alternatives to this so that the .ContainsKey() method of the dictionary doesn't differentiate between casing?
Yes - pass the Dictionary constructor StringComparer.OrdinalIgnoreCase (or another case-ignoring comparer, depending on your culture-sensitivity needs).
By using a StringDictionary the keys are converted to lower case at creating time.
http://simiansoftware.blogspot.com/2008/11/have-const-string-with-ui-description.html
You could use the var keyword to remove some clutter. Technically the source remains the same. Also I would just pass and return a Dictionary<string, string> because you're not doing anything with that ILanguage parameter and make the method more reusable:
private static IDictionary<string, string> ConvertKeysToLowerCase(
IDictionary<string, string> dictionaries)
{
var convertedDictionatry = new Dictionary<string, string>();
foreach(string key in dictionaries.Keys)
{
convertedDictionatry.Add(key.ToLower(), dictionaries[key]);
}
return convertedDictionatry;
}
... and call it like so:
// myLanguageDictionaries is of type IDictionary<ILanguage, IDictionary<string, string>>
foreach (var dictionary in myLanguageDictionaries.Keys)
{
myLanguageDictionaries[dictionary].Value =
ConvertKeysToLowerCase(myLanguageDictionaries[dictionary].Value);
}
You could inherit from IDictionary yourself, and simply marshal calls to an internal Dictionary instance.
Add(string key, string value) { dictionary.Add(key.ToLowerInvariant(), value) ; }
public string this[string key]
{
get { return dictionary[key.ToLowerInvariant()]; }
set { dictionary[key.ToLowerInvariant()] = value; }
}
// And so forth.
System.Collections.Specialized.StringDictionary() may help. MSDN states:
"The key is handled in a case-insensitive manner; it is translated to lowercase before it is used with the string dictionary.
In .NET Framework version 1.0, this class uses culture-sensitive string comparisons. However, in .NET Framework version 1.1 and later, this class uses CultureInfo.InvariantCulture when comparing strings. For more information about how culture affects comparisons and sorting, see Comparing and Sorting Data for a Specific Culture and Performing Culture-Insensitive String Operations."
You can also try this way
convertedDictionatry = convertedDictionatry .ToDictionary(k => k.Key.ToLower(), k => k.Value.ToLower());
LINQ version using the IEnumerable<T> extension methods:
private static IDictionary<ILanguage, IDictionary<string, string>> ConvertKeysToLowerCase(
IDictionary<ILanguage, IDictionary<string, string>> dictionaries)
{
return dictionaries.ToDictionary(
x => x.Key, v => CloneWithComparer(v.Value, StringComparer.OrdinalIgnoreCase));
}
static IDictionary<K, V> CloneWithComparer<K,V>(IDictionary<K, V> original, IEqualityComparer<K> comparer)
{
return original.ToDictionary(x => x.Key, x => x.Value, comparer);
}
Related
I wrote a method that collected errors through the process (instead of failing on the first error). This is more for validation. It worked something like this.
var errors = new Dictionary<string, string[]>();
// Do some work, and if error
errors.AddOrUpdate(nameof(object.Property), "Specific error message.");
And this used the custom extension I wrote for Dictionary.
public static void AddOrUpdate(this Dictionary<string, string[]> dictionary, string key, string value)
{
dictionary.AddOrUpdate(key, new [] { value });
}
public static void AddOrUpdate(this Dictionary<string, string[]> dictionary, string key, string[] values)
{
if (dictionary.ContainsKey(key))
{
dictionary[key] = dictionary[key].Concat(values).ToArray();
}
else
{
dictionary.Add(key, values);
}
}
During review, my co-worker suggested using ConcurrentDictionary. To which I came up with this:
var errors = new ConcurrentDictionary<string, string[]>();
// Do some work, and if error
var errorMessage = $"{input.PurchaseOrder} - Purchase Orders require a contact email address.";
errors.AddOrUpdate(nameof(input.ContactEmail),
new[] { errorMessage },
(k,oldValue) => ConcurrentDictionaryHelper.AddStringToArray(oldValue, errorMessage));
With the helper method:
public static string[] AddStringToArray(string[] values, string newValue)
{
var valuesList = values.ToList();
valuesList.Add(newValue);
return valuesList.ToArray();
}
While I see the power in ConcurrentDictionary allowing the functions, I'm having a hard time seeing how it is an improvement in this case. I felt my implementation was more intuitive.
Am I missing something? Or is this more a matter of preference in this case?
ConcurrentDictionary is useful if you're running operations add/remove from differents threads. If your validation runs in a single thread, then you can keep the Dictionary<string, string[]>.
A recomendation: change the dictionary type to Dictionary<string, HashSet<string>> this way you will avoid duplicated errors(if any) and it will have a much better performance (currently you're concatenating string arrays).
Here is an extension:
public static class DictionaryExtensions
{
public static void AddValidationError(
this IDictionary<string, HashSet<string>> dictionary,
[NotNull] string property,
[NotNull] string error)
{
if (!dictionary.TryGetValue(property, out var errors))
errors = new HashSet<string>();
errors.Add(error);
}
}
ConcurrentDictionary is thread safe, so you won't get exceptions when multiple threads will attempt to write to the same Dictionary at the same time.
You could use a Dictionary of lists, this way you won't need to convert from array to list and back.
Here is a generic implementation:
public static TList AddToList<TKey, TValue, TList>(this IDictionary<TKey, TList> target, TKey key, params TValue[] values)
where TList : ICollection<TValue>, new()
{
TList theReturn;
lock (target)
{
if (!target.TryGetValue(key, out theReturn))
{
theReturn = new TList();
target.Add(key, theReturn);
}
}
lock (theReturn)
{
foreach (var currentValue in values)
{
theReturn.Add(currentValue);
}
}
return theReturn;
}
I have 2 data structures: Dictionary<string, string> and Multimap<string, string>.
Multimap is really just a Dictionary under the hood. I took must of the code from this question. Here's the class definition:
public class Multimap<TKey, TValue> : Dictionary<TKey, HashSet<TValue>>
{ ... }
Both data structures have a .Add(TKey key, TValue value) method.
I have a class that is responsible for populating these maps from certain files. I currently have the following two methods:
public Dictionary<string, string> PopulateDictionary(...)
{
Dictionary<string, string> returnDictionary = new Dictionary<string, string>();
...
foreach (...)
{
...
returnDictionary.Add(key, value);
}
return returnDictionary;
}
public Multimap<string, string> PopulateMultimap(...)
{
Multimap<string, string> returnMultimap = new Multimap<string, string>();
...
foreach (...)
{
...
returnMultimap.Add(key, value);
}
return returnMultimap;
}
As you can see, they're exactly the same, both around 25 lines long, and the only difference is their return type. What I am looking to do is condense this into one method.
My first attempt was to have the method
public Dictionary<string, object> PopulateGenericDictionary(...)
{ ... }
Where object was either string or HashSet<string>. But I didn't have much luck casting from Dictionary<string, object> to Multimap<string, string>.
Extracting the logic out of the methods is an option, but it's not great. Because of the foreach loops, there's always going to be some logic inside the two methods. You do end up with methods that are twice as small, but there's still two identical methods, which doesn't truly solve the problem.
This would be my ideal method structure:
public Dictionary<string, string> PopulateDictionary(...)
{
return MethodThatDoesAllTheLogic(...);
}
public Multimap<string, string> PopulateMultimap(...)
{
return MethodThatDoesAllTheLogic(...);
}
public ??? MethodThatDoesAllTheLogic(...)
{ ... }
I've been fiddling around with casting and generics, but I just can't get it to work. Any ideas?
Edit
I have used millimoose's solution. Here's my code now:
public Dictionary<string, string> GenerateDictionary(...)
{
Dictionary<string, string> returnMap = new Dictionary<string, string>();
PopulateDictionary(returnMap.Add, ...);
return returnMap;
}
public Multimap<string, string> GenerateMultimap(...)
{
Multimap<string, string> returnMap = new Multimap<string, string>();
PopulateDictionary(returnMap.Add, ...);
return returnMap;
}
private static void PopulateGenericDictionary(Action<string, string> addFunc, ...)
{
...
foreach (...)
{
addFunc(key, value);
}
}
Much cleaner!
To work around the lack of a common interface, you can invent one ad-hoc using a bunch of delegate type parameters:
void MethodThatDoesAllTheLogic(Action<string, string> addFunc)
{
// ...
addFunc(key, value);
// ...
}
public Dictionary<...> PopulateDictionary()
{
// ...
MethodThatDoesAllTheLogic(result.Add);
}
(Adding more parameters as necessary.)
I would avoid having the helper method create the actual collection at all; have it just populate an existing collection. That can be done much more effectively, since the Add method has the same signature in both cases. We can just use a delegate to accept the Add method:
public static void PopulateMapping<TKey, TValue>(Action<TKey, TValue> addMethod,
IEnumerable<TKey> data) //include other parameters needed to populate the data
{
foreach (var key in data)
{
addMethod(key, default(TValue));
}
}
Then it would be used like this:
public static Dictionary<string, string> PopulateDictionary()
{
Dictionary<string, string> output = new Dictionary<string, string>();
PopulateMapping<string, string>(output.Add, new string[] { "a" });
return output;
}
If you are only looking for an Add method, then both objects should share IDictionary. However, that Add method only uses objects. That is probably the closest that you can get without having to use generics in the method...but again you lose the benefits of generics at that point.
See if this approach will be useful:
The key is to make abstraction on creation of the object (Dictionary or Multimap) and aquiring the values - the two differences in the populating method.
public Dictionary<string, TValue> Populate<TValue>( Dictionary<string, TValue> returnDict, Func<SomeType, TValue> valueProvider)
{
string key = null;
...
foreach (...)
{
...
returnDict.Add(key, valueProvider(value));
}
return returnDict;
}
The example invocation is can be:
public void Test()
{
Populate(new Multimap<string, HashSet<string>>(), (t) => new HashSet<HashSet<string>>());
}
I'm not sure if the valueProvider delegate will be suited to your problem. Try to give more information about it.
If your inner logic is truly identical except for what type TValue is - and I mean word-for-word identical - then you could do something like:
IDictionary<string, TValue> MethodThatDoesAllTheLogic<TValue>(whatever)
{
// word for word-identical logic
}
I made the method take TValue as its only type parameter because that's the only difference (in the example you showed): both methods have string as the first type parameter.
ETA: This assumes that MultiMap implements IDictionary<K,V>. Since you said that it inherited from Dictionary<K,V> I assumed that it did.
in C# with generics you can require them to extend or implement a specific class in our case Dictionary, the following is how you might achieve that.
public T Populate<T>(string val) where T : Dictionary<string, string>, new()
{
T returnDict = new T();
returnDict.Add("key", "val");
return returnDict;
}
My scenario,
how to convert List<KeyValuePair<string, string>> into IDictionary<string, string>?
Very, very simply with LINQ:
IDictionary<string, string> dictionary =
list.ToDictionary(pair => pair.Key, pair => pair.Value);
Note that this will fail if there are any duplicate keys - I assume that's okay?
Or you can use this extension method to simplify your code:
public static class Extensions
{
public static IDictionary<TKey, TValue> ToDictionary<TKey, TValue>(
this IEnumerable<KeyValuePair<TKey, TValue>> list)
{
return list.ToDictionary(x => x.Key, x => x.Value);
}
}
Use ToDictionary() extension method of the Enumerable class.
You can also use the constructor overload of Dictionary<TKey,TValue> that takes an IEnumerable<KeyValuePair<TKey,TValue>> as parameter.
var list = new List<KeyValuePair<int, string>>();
var dictionary = new Dictionary<int, string>(list);
I have the following List :
List<Dictionary<int, Dictionary<string, string>>> lngList
lngList.Add(new Dictionary<int,Dictionary<string,string>>().Add(1,new Dictionary<string,string>().Add("Item1Key","Item1Value")));
lngList.Add(new Dictionary<int,Dictionary<string,string>>().Add(3,new Dictionary<string,string>().Add("Item1Key","Item1Value")));
lngList.Add(new Dictionary<int,Dictionary<string,string>>().Add(2,new Dictionary<string,string>().Add("Item1Key","Item1Value")));
lngList.Add(new Dictionary<int,Dictionary<string,string>>().Add(4,new Dictionary<string,string>().Add("Item1Key","Item1Value")));
I need to sort (ascending) this list on the basis of the integer value present inside the Dictionary.
This has to be achieved without using LINQ.
P.S. This is assuming all the the integer values added are unique.
If each dictionary has only one key, and you don’t care what happens if it has multiple, you can do this:
lngList.Sort((a, b) => a.Keys.First().CompareTo(b.Keys.First()));
Since you stated that “This has to be achieved without using LINQ”, I assume you mean that the System.Linq namespace is not available to you. But that’s not a problem: you only need .First(), which you can easily define yourself:
public static class EnumerableExtensions {
public static T First<T>(this IEnumerable<T> source) {
using (var e = source.GetEnumerator()) {
if (!e.MoveNext())
throw new InvalidOperationException("The collection is empty.");
return e.Current;
}
}
}
If you have to use .NET 2.0, which doesn’t have lambda expressions or extension methods, use this instead:
lngList.Sort(new Comparison<Dictionary<int, Dictionary<string, string>>>(sortFunc));
public int sortFunc(Dictionary<int, Dictionary<string, string>> a,
Dictionary<int, Dictionary<string, string>> b)
{
return First(a.Keys).CompareTo(First(b.Keys));
}
public static T First<T>(IEnumerable<T> source) {
using (var e = source.GetEnumerator()) {
if (!e.MoveNext())
throw new InvalidOperationException("The collection is empty.");
return e.Current;
}
}
The easiest way to solve your solution is to use a SortedList instead of a List:
example:
SortedList<int, Dictionary<string, string>> lngList;
this will be sorted by default on the integer value
I need to add key/object pairs to a dictionary, but I of course need to first check if the key already exists otherwise I get a "key already exists in dictionary" error. The code below solves this but is clunky.
What is a more elegant way of doing this without making a string helper method like this?
using System;
using System.Collections.Generic;
namespace TestDictStringObject
{
class Program
{
static void Main(string[] args)
{
Dictionary<string, object> currentViews = new Dictionary<string, object>();
StringHelpers.SafeDictionaryAdd(currentViews, "Customers", "view1");
StringHelpers.SafeDictionaryAdd(currentViews, "Customers", "view2");
StringHelpers.SafeDictionaryAdd(currentViews, "Employees", "view1");
StringHelpers.SafeDictionaryAdd(currentViews, "Reports", "view1");
foreach (KeyValuePair<string, object> pair in currentViews)
{
Console.WriteLine("{0} {1}", pair.Key, pair.Value);
}
Console.ReadLine();
}
}
public static class StringHelpers
{
public static void SafeDictionaryAdd(Dictionary<string, object> dict, string key, object view)
{
if (!dict.ContainsKey(key))
{
dict.Add(key, view);
}
else
{
dict[key] = view;
}
}
}
}
Just use the indexer - it will overwrite if it's already there, but it doesn't have to be there first:
Dictionary<string, object> currentViews = new Dictionary<string, object>();
currentViews["Customers"] = "view1";
currentViews["Customers"] = "view2";
currentViews["Employees"] = "view1";
currentViews["Reports"] = "view1";
Basically use Add if the existence of the key indicates a bug (so you want it to throw) and the indexer otherwise. (It's a bit like the difference between casting and using as for reference conversions.)
If you're using C# 3 and you have a distinct set of keys, you can make this even neater:
var currentViews = new Dictionary<string, object>()
{
{ "Customers", "view2" },
{ "Employees", "view1" },
{ "Reports", "view1" },
};
That won't work in your case though, as collection initializers always use Add which will throw on the second Customers entry.
What's wrong with...
dict[key] = view;
It'll automatically add the key if it's non-existent.
simply
dict[key] = view;
From the MSDN documentation of Dictionary.Item
The value associated with the
specified key. If the specified key is
not found, a get operation throws a
KeyNotFoundException, and a set
operation creates a new element with
the specified key.
My emphasis
As usual John Skeet gets in there with lighting speed with the right answer, but interestingly you could also have written your SafeAdd as an Extension Method on IDictionary.
public static void SafeAdd(this IDictionary<K, T>. dict, K key, T value)...
Although using the indexer is clearly the right answer for your specific problem, another more general answer to the problem of adding additional functionality to an existing type would be to define an extension method.
Obviously this isn't a particularly useful example, but something to bear in mind for the next time you find a real need:
public static class DictionaryExtensions
{
public static void SafeAdd<TKey, TValue>(this Dictionary<TKey, TValue> dict,
TKey key, TValue value)
{
dict[key] = value;
}
}