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
Related
This question already has answers here:
How to flatten a dictionary<string,List<string>> in linq and keep the key in the results
(3 answers)
Closed 5 years ago.
So, basically I'm implementing a MultiMap in C# and I'm taking the obvious approach: using a Dictionary object that uses a List as the value. Next, I need to return a flattened list of key value pairs: List<KeyValuePair<TKey, TValue>>. It's not so bad to do it using loops, but I'm curious about how to get this done with Linq.
I got close using the SelectMany function, but I couldn't quite figure out how to get from point A to point B. Here's my code that does it without Linq (minus the other bits you don't care about).
public class MultiDict<TKey, TValue>
{
private Dictionary<TKey, List<TValue>> _dict = new Dictionary<TKey, List<TValue>>();
public void AddValue(TKey key, TValue val)
{
List<TValue> list;
if (_dict.ContainsKey(key))
{
list = _dict[key];
}
else
{
list = new List<TValue>();
_dict.Add(key, list);
}
list.add(val);
}
public KeyValuePair<TKey, TValue>[] Flattened()
{
var flattened = new List<KeyValuePair<TKey, TValue>>();
foreach (var pair in _dict)
{
//pair.Value is actually a List<TValue> object that we have to
// iterate through as well
foreach (var val in pair.Value)
{
flattened.add(new KeyValuePair<TKey, TValue>(pair.Key, val));
}
}
return flattened.ToArray();
}
}
So if I used it like this:
var multiDict = new MultiDict<int, string>();
multiDict.Add(1, "King");
multiDict.Add(1, "Boomy");
multiDict.Add(3, "Aang");
var results = multiDict.Flattened();
I should get three KeyValuePairs in results.
The select many will flatten out the a nested array. The Value.Select creates a KVP for each item in the sublist, the select many then converts the nested array into a flatten collection.
public KeyValuePair<TKey, TValue>[] Flattened()
{
return _dict.SelectMany(x => x.Value.Select(v => new KeyValuePair<TKey, TValue>(x.Key, v))).ToArray();
}
I want to define a new member method for Dictionary as it already built in member methods e.g. Add(), Clear(), ContainsKey() etc.
That newly added member method should return all the keyvaluepairs in form of a Set as we can return map.entrySet() to Set in Java.
Can existing methods for dictionary be overridden to achieve this ?
You could create an extension method:
using System;
using System.Collections.Generic;
using System.Linq;
public static class DictionaryExtensions {
public static HashSet<KeyValuePair<TKey, TValue>> ToSet<TKey, TValue>(this Dictionary<TKey, TValue> dict) {
return new HashSet<KeyValuePair<TKey, TValue>>(dict.ToList());
}
}
Info about extension methods: https://msdn.microsoft.com/en-us/library/bb383977(v=vs.110).aspx
I'm aware it's not a set, but by using Linq you can get a list of key value pairs like so:
Dictionary<string, string> dictionary = new Dictionary<string, string>();
List<KeyValuePair<string, string>> keyValuePairs = dictionary.ToList();
Just in case it helps, you can access KeyValue pair of the Dictionary like this :
// Example dictionary
var dic = new Dictionary<int, string>{{1, "a"}};
foreach (var item in dic)
{
Console.WriteLine(string.Format("key : {0}, Value : {1}", item.Key, item.Value));
}
I'd like to create a Dictionary object, with string Keys, holding values which are of a generic type. I imagine that it would look something like this:
Dictionary<string, List<T>> d = new Dictionary<string, List<T>>();
And enable me to add the following:
d.Add("Numbers", new List<int>());
d.Add("Letters", new List<string>());
I know that I can do it for a list of strings, for example, using this syntax:
Dictionary<string, List<string>> d = new Dictionary<string, List<string>>();
d.Add("Key", new List<string>());
but I'd like to do it for a generic list if possible...
2 questions then:
Is it possible?
What's the syntax?
EDIT: Now I've reread the question...
You can't do this, but a custom collection would handle it to some extent. You'd basically have a generic Add method:
public void Add<T>(string key, List<T> list)
(The collection itself wouldn't be generic - unless you wanted to make the key type generic.)
You couldn't extract values from it in a strongly typed manner though, because the compiler won't know which type you've used for a particular key. If you make the key the type itself, you end with a slightly better situation, but one which still isn't supported by the existing collections. That's the situation my original answer was responding to.
EDIT: Original answer, when I hadn't quite read the question correctly, but which may be informative anyway...
No, you can't make one type argument depend on another, I'm afraid. It's just one of the things one might want to express in a generic type system but which .NET's constraints don't allow for. There are always going to be such problems, and the .NET designers chose to keep generics relatively simple.
However, you can write a collection to enforce it fairly easily. I have an example in a blog post which only keeps a single value, but it would be easy to extend that to use a list.
Would something like this work?
public class GenericDictionary
{
private Dictionary<string, object> _dict = new Dictionary<string, object>();
public void Add<T>(string key, T value) where T : class
{
_dict.Add(key, value);
}
public T GetValue<T>(string key) where T : class
{
return _dict[key] as T;
}
}
Basically it wraps all the casting behind the scenes for you.
How about Dictionary<string, dynamic>? (assuming you're on C# 4)
Dictionary<string, dynamic> Dict = new Dictionary<string, dynamic>();
Source: https://stackoverflow.com/a/5038029/3270733
I prefer this way of putting generic types into a collection:
interface IList
{
void Add (object item);
}
class MyList<T> : List<T>, IList
{
public void Add (object item)
{
base.Add ((T) item); // could put a type check here
}
}
class Program
{
static void Main (string [] args)
{
SortedDictionary<int, IList>
dict = new SortedDictionary<int, IList> ();
dict [0] = new MyList<int> ();
dict [1] = new MyList<float> ();
dict [0].Add (42);
dict [1].Add ("Hello"); // Fails! Type cast exception.
}
}
But you do lose the type checks at compile time.
I came to a type safe implementation using ConditionalWeakTable.
public class FieldByType
{
static class Storage<T>
where T : class
{
static readonly ConditionalWeakTable<FieldByType, T> table = new ConditionalWeakTable<FieldByType, T>();
public static T GetValue(FieldByType fieldByType)
{
table.TryGetValue(fieldByType, out var result);
return result;
}
public static void SetValue(FieldByType fieldByType, T value)
{
table.Remove(fieldByType);
table.Add(fieldByType, value);
}
}
public T GetValue<T>()
where T : class
{
return Storage<T>.GetValue(this);
}
public void SetValue<T>(T value)
where T : class
{
Storage<T>.SetValue(this, value);
}
}
It can be used like this:
/// <summary>
/// This class can be used when cloning multiple related objects to store cloned/original object relationship.
/// </summary>
public class CloningContext
{
readonly FieldByType dictionaries = new FieldByType();
public void RegisterClone<T>(T original, T clone)
{
var dictionary = dictionaries.GetValue<Dictionary<T, T>>();
if (dictionary == null)
{
dictionary = new Dictionary<T, T>();
dictionaries.SetValue(dictionary);
}
dictionary[original] = clone;
}
public bool TryGetClone<T>(T original, out T clone)
{
var dictionary = dictionaries.GetValue<Dictionary<T, T>>();
if (dictionary == null)
{
clone = default(T);
return false;
}
return dictionary.TryGetValue(original, out clone);
}
}
See also this question where the type of the values is stored in as a generic parameter of the keys.
We're using lots of reflection to create an extensible administration tool. We needed a way to register items in the global search in the module definition. Each search would return results in a consistent way, but each one had different dependencies. Here's an example of us registering search for a single module:
public void ConfigureSearch(ISearchConfiguration config)
{
config.AddGlobalSearchCallback<IEmploymentDataContext>((query, ctx) =>
{
return ctx.Positions.Where(p => p.Name.Contains(query)).ToList().Select(p =>
new SearchResult("Positions", p.Name, p.ThumbnailUrl,
new UrlContext("edit", "position", new RouteValueDictionary(new { Id = p.Id }))
));
});
}
In the background during module registration, we iterate over every module and add the Func to a SearchTable with an instance of:
public class GenericFuncCollection : IEnumerable<Tuple<Type, Type, Object>>
{
private List<Tuple<Type, Type, Object>> objects = new List<Tuple<Type, Type, Object>>();
/// <summary>
/// Stores a list of Func of T where T is unknown at compile time.
/// </summary>
/// <typeparam name="T1">Type of T</typeparam>
/// <typeparam name="T2">Type of the Func</typeparam>
/// <param name="func">Instance of the Func</param>
public void Add<T1, T2>(Object func)
{
objects.Add(new Tuple<Type, Type, Object>(typeof(T1), typeof(T2), func));
}
public IEnumerator<Tuple<Type, Type, object>> GetEnumerator()
{
return objects.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return objects.GetEnumerator();
}
}
Then when we finally call it, we do it with reflection:
var dependency = DependencyResolver.Current.GetService(search.Item1);
var methodInfo = search.Item2.GetMethod("Invoke");
return (IEnumerable<SearchResult>)methodInfo.Invoke(search.Item3, new Object[] { query, dependency });
I didn't find what I was looking for here but after reading I think it might be what is being asked for so an attempt to answer.
The problem is that when you use Dictionary it is a closed constructed type and all elements must be of the TValue type. I see this question in a number of places without a good answer.
Fact is that I want indexing but each element to have a different type and based on the value of TKey we already know the type. Not trying to get around the boxing but trying to simply get more elegant access something like DataSetExtensions Field. And don't want to use dynamic because the types are known and it is just not wanted.
A solution can be to create a non generic type that does not expose T at the class level and therefore cause the TValue part of the dictionary to be closed constructed. Then sprinkle in a fluent method to help initialization.
public class GenericObject
{
private object value;
public T GetValue<T>()
{
return (T)value;
}
public void SetValue<T>(T value)
{
this.value = value;
}
public GenericObject WithValue<T>(T value)
{
this.value = value;
return this;
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<string, GenericObject> dict = new Dictionary<string, GenericObject>();
dict["mystring"] = new GenericObject().WithValue<string>("Hello World");
dict["myint"] = new GenericObject().WithValue<int>(1);
int i = dict["myint"].GetValue<int>();
string s = dict["mystring"].GetValue<string>();
}
}
Other posibility it's to use the variable dynamic.
For example:
Dictionary<string, List<dynamic>> d = new Dictionary<string, List<dynamic>>();
d.Add("Key", new List<dynamic>());
the variable dynamic resolve the type on runtime.
No, but you can use object instead of generic type.
Long answer:
The current version of C# will not allow you to make entries of generic type in a dictionary. Your options are either a) create a custom class that is the same as a dictionary except allow it to accept generic types, or b) make your Dictionary take values of type object. I find option b to be the simpler approach.
If you send lists of specific types, then when you go to process the lists you will have to test to see what kind of list it is. A better approach is to create lists of objects; this way you can enter integers, strings, or whatever data type you want and you don't necessarily have to test to see what type of object the List holds. This would (presumably) produce the effect you're looking for.
Here is a short console program that does the trick:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace dictionary
{
class Program
{
static void Main(string[] args)
{
Dictionary<string, object> dic = new Dictionary<string, object>();
var lstIntList = new List<object>();
var lstStrings = new List<object>();
var lstObjects = new List<object>();
string s = "";
lstIntList.Add(1);
lstIntList.Add(2);
lstIntList.Add(3);
lstStrings.Add("a");
lstStrings.Add("b");
lstStrings.Add("c");
dic.Add("Numbers", lstIntList);
dic.Add("Letters", lstStrings);
foreach (KeyValuePair<string, object> kvp in dic)
{
Console.WriteLine("{0}", kvp.Key);
lstObjects = ((IEnumerable)kvp.Value).Cast<object>().ToList();
foreach (var obj in lstObjects)
{s = obj.ToString(); Console.WriteLine(s);}
Console.WriteLine("");
}
Console.WriteLine("");
Console.WriteLine("press any key to exit");
Console.ReadKey();
}//end main
}
}
One of the way is to create a Dictionary value with type "object" like:
Dictionary<string, object> d = new Dictionary<string, object>();
So, here object datatype is used as a generic datatype, you can put anything in this as a value.
Or it's possible to use generic Type like this
public static void SafeUpdateInDictionary<T, L>(T DictionaryToBeUpdated, string Key, L Value) where T : Dictionary<string, L>
{
if (DictionaryToBeUpdated != null)
{
if(Value != null)
{
if (!DictionaryToBeUpdated.ContainsKey(Key))
DictionaryToBeUpdated.Add(Key, Value);
else
DictionaryToBeUpdated[Key] = Value;
}
}
}
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;
}
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);
}