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();
}
Related
I have an IDictionary<string, MyEnum?> collection that needs to be passed to a class to wrap it in a IReadOnlyDictionary<string, MyEnum> (note MyEnum but not MyEnum?).
I have come up with two designs:
Delay the wrapping to IReadOnlyDictionary<string, MyEnum> until property access:
public class MyClass
{
private readonly IEnumerable<KeyValuePair<string, MyEnum?>> _kvps;
public MyClass(IEnumerable<KeyValuePair<string, MyEnum?>> kvps)
{
_kvps = kvps;
}
public IReadOnlyDictionary<string, MyEnum> Kvps
{
get
{
var filtered = from kvp in _kvps
where kvp.Value.HasValue
select kvp;
return new ReadOnlyDictionary<string, MyEnum>(
filtered.ToDictionary(kvp => kvp.Key, kvp => (MyEnum)kvp.Value);
}
}
}
Eagerly evaluate the collection in constructor
public class MyClass
{
public MyClass(IEnumerable<KeyValuePair<string, MyEnum?>> kvps)
{
Kvps = ToReadOnly(kvps);
}
public IReadOnlyDictionary<string, MyEnum> Kvps { get; }
private static IReadOnlyDictionary<string, MyEnum> ToReadOnly(
IEnumerable<KeyValuePair<string, MyEnum?>> kvps)
{
var filtered = from kvp in kvps
where kvp.Value.HasValue
select kvp;
return new ReadOnlyDictionary<string, MyEnum>(
filtered.ToDictionary(kvp => kvp.Key, kvp => (MyEnum)kvp.Value);
}
}
The constructor design section of the Framework Design Guidelines suggests that minimal work should be done in constructors so I am opting for the first approach. However, that means every call to MyClass.Kvps will trigger a copy of _kvps which is not ideal.
I would like to know which is a better approach (or are there other ways) in terms of:
Memory efficiency (ideally only one copy of the collection is stored in MyClass)
Performance (property access should be fast and should not trigger a copy of the KeyValuePairs)
Out of the two requirements - don't copy the key value pairs and don't store two copies - you'll have to break one.
What causes us to look at this and think that there must be a solution is that we see TValue and TValue? and our minds want to see them as being of the same type. But they are not the same type.
It becomes clearer if you imagine that instead of TValue and TValue? that these are two different types, like an int and a string, and we want to project a collection of one to a collection of the other while filtering. For example,
List<string> GetStringsFromNonNegativeInts(List<int> ints)
{
return ints.Where(i=>i>-1).Select(i=>i.ToString()).ToList();
}
That's exactly the same scenario as trying to filter a set of TValue? to a set of TValue, even without the dictionary. It's just harder to see. TValue and TValue? code-blind us.
There are only two ways to do this. One is to copy each time, and the other is to keep two lists in synchronization.
EDIT: If you want the latest source values, best way is to implement your own class that implements IReadOnlyDictionary. Initialize this with a private field of ReadOnlyDictionary<string, MyEnum?>. Each call will do the lookup, and if the key exists AND HasValue, return the value.
Note that this implementation depends on the reference to the original values being passed in as an IReadOnlyDictionary to avoid having to copy values over.
public class MyReadOnlyDictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue> where TValue : struct
{
// other methods to implement here...
public MyReadOnlyDictionary(IReadOnlyDictionary<TKey, TValue?> kvps)
{
_kvps = kvps;
}
private IReadOnlyDictionary<TKey, TValue?> _kvps;
new public TValue this[TKey key]
{
get
{
TValue? val = _kvps[key];
if (val.HasValue)
return val.Value;
throw new KeyNotFoundException();
}
}
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Creating a constant Dictionary in C#
I currently have:
public string GetRefStat(int pk) {
return RefStat[pk];
}
private readonly Dictionary<int, int> RefStat =
new Dictionary<int, int>
{
{1,2},
{2,3},
{3,5}
};
This works but the only time I use the RefStat dictionary is when it is called by GetRefStat.
Is there a way I can combine the method and the dictionary?
Something like this?
public string GetRefStat(int pk)
{
return new Dictionary<int, int>
{
{1,2},
{2,3},
{3,5}
}[pk];
}
Yes, you can init the dictionary in the type's constructor. You can then change method GetRefStat to a property. So the meta code may look like this
class Foo
{
public Dictionary<int, int> RefStat {get;private set;}
Foo()
{
RefStat = new Dictionary<int, int>
{
{1,2},
{2,3},
{3,5}
};
}
}
And usage
Foo f = new Foo();
var item = f.RefStat[0]
Well you can make an extension method and then all dictionaries can use the function. I am going to assume that GetRefStat will be more than simply grabbing a value from a dictionary with a key:
public static class DictionaryExtensions
{
public static TValue GetRefStat<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key)
{
return dictionary[key];
}
}
Then all dictionaries can call it like:
var dictionary = new Dictionary<int, int>
{
{1,2},
{2,3},
{3,5}
};
var value = dictionary.GetRefStat(2)
If this dictionary is a bunch of constants then this answer is overkill. Just use if/else or switch.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Bidirectional 1 to 1 Dictionary in C#
Im curious if a datastructure exists in the standard .net libraries that can represent a 1-1 relationship, such as the following
1-a
4-b
6-c
5-d
Where I can say:
thisstructure[1] // returns "a"
thisstructure.GetKey["d"] // return 5
I understand all keys would have to be unique, does anything similar exist?
Thanks!
Yes- it's called KeyedCollection. It is intended to be subclassed and provides indexed access as well as access by a property derived from the added item. I usually make a generic subclass:
public class GenericKeyedCollection<TKey, TValue> : KeyedCollection<TKey, TValue> {
private readonly Func<TValue, TKey> _keyGenerator;
public GenericKeyedCollection(Func<TValue, TKey> keyGenerator) {
_keyGenerator = keyGenerator;
}
protected override int GetKeyForItem(TValue item)
{
return _keyGenerator(item);
}
}
To use it:
var myCollection = new GenericKeyedCollection<String, Car>(c=>c.Model);
myCollection.Add(new Car("Ford", "Mustang"));
var byIndex = myCollection[0];
var byModel = myCollection["Mustang"];
The only caveat is that the derived property (the "key") mustn't change after the item has been added.
If your key is not a property of the value, then you can use a Tuple<T1, T2> to combine the key and value:
var myCollection = new GenericKeyedCollection<String, Tuple<String, Car>>(t=>t.Item1);
myCollection.Add(new Tuple<String, Car>("Foo", Car("Ford", "Mustang")));
var byIndexCar = myCollection[0].Item2;
var byItem1Car = myCollection["Foo"].Item2;
Could this method fit your needs?
public static class Extensions
{
public static TKey GetKey<TKey, TValue>(this Dictionary<TKey, TValue> dict, TValue value)
{
int index = dict.Values.ToList().IndexOf(value);
if (index == -1)
{
return default(TKey); //or maybe throw an exception
}
return dict.Keys.ToList()[index];
}
}
You could then use it like so:
Dictionary<int, char> dict = new Dictionary<int, char>();
dict.Add(1, 'a');
dict.Add(4, 'b');
dict.Add(6, 'c');
dict.Add(5, 'd');
Console.WriteLine(dict.GetKey('d')); //5
The Dictionary....or IDictionary interface is the closest I can think of to what you want. It doesn't have quite so simple a searching operation, in that searching on a value can return the key, but I do know you can search on a key to get a value. providing functionality for the reverse in a custom extended class wouldn't be difficult at all.
MSDN IDictionary page
Suppose I have a method to return a list of keys in a dictionary, sorted by their values:
/// Perhaps a wildly inefficient way to achieve this!
public static List<K> SortByValues<K,V>( Dictionary<K,V> items )
{
var keys = new K[items.Count];
var values = new V[items.Count];
var index = 0;
foreach( var kvp in items )
{
keys[index] = kvp.Key;
values[index++] = kvp.Value;
}
Array.Sort( values, keys );
return new List<K>( keys );
}
I would like to offer an overload that accepts an IComparer to pass to the Array.Sort method. Is there any way to do this without duplicating all of the code? Ideally there'd be some way to get at the "default" comparer for the type V.
Like Comparer<V>.Default, maybe?
You could just change SortByValues to take an IComparer<V> argument and then have an overload call that method passing Comparer<V>.Default:
public static List<K> SortByValues<K,V>(Dictionary<K,V> items)
{
SortByValues(items, Comparer<K>.Default);
}
public static List<K> SortByValues<K,V>(Dictionary<K,V> items, IComparer<K> comparer)
{
var keys = new K[items.Count];
var values = new V[items.Count];
var index = 0;
foreach( var kvp in items )
{
keys[index] = kvp.Key;
values[index++] = kvp.Value;
}
Array.Sort( values, keys, comparer );
return new List<K>( keys );
}
It looks like you're trying to discover way to get a default value for an IComparer<V> for a given generic parameter V. If so then you are looking for the Comparer<T>.Default property (or EqualityComparer<T> if doing straight equality).
With that it hand you can use the following pattern for accepting custom comparers.
public static List<K> SortByValues<K,V>( Dictionary<K,V> items) {
return SortByValues(items, Comparer<V>.Default);
}
public static List<K> SortByValues<K,V>(
Dictionary<K,V> items,
IComparer<V> comparer) {
...
}
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