Transform Dictionary<string, int> to Dictionary<int, List<string>> - c#

Q How can I most efficiently convert a Dictionary<string, int> to a Dictionary<int, List<string>>?
Example
var input = new Dictionary<string, int>() { {"A", 1}, {"B", 1}, {"C", 2} ...
Dictionary<int, List<string>> result = Transform(input)
Assert.IsTrue(result, { {1, {"A", "B"}}, {2, {"C"}} ... });

Group the dictionary by values and map the group keys to list of keys:
input.GroupBy(x => x.Value).ToDictionary(x => x.Key, x => x.Select(_ => _.Key).ToList())

How about this?
var result =
dict.ToLookup(x => x.Value, x => x.Key)
.ToDictionary(y => y.Key, y => y.ToList());
Although I don't see why you couldn't just use the result from dict.ToLookup() without changing it to a dictionary, for example:
var dict = new Dictionary<string, int>
{
{"One", 1},
{"Two", 2},
{"1", 1},
{"TWO", 2},
{"ii", 2}
};
var test = dict.ToLookup(x => x.Value, x => x.Key);
Console.WriteLine(string.Join(", ", test[2])); // Prints: Two, TWO, ii

You can use Linq to achieve.
private static Dictionary<int, List<string>> Transform(Dictionary<string, int> input)
{
var result = new Dictionary<int, List<string>>();
foreach (var value in input.Select(x => x.Value).Distinct())
{
var lst = input.Where(x => x.Value == value).Select(x => x.Key).ToList();
result.Add(value, lst);
}
return result;
}

Related

C# Intersect Two Dictionaries and Store The Key and The Two Values in a List

I want to intersect the 2 dictionaries, but I am not sure how to store historicalHashTags[x] too, I managed to store only the key and value of 1 dictionary.
var intersectedHashTags = currentHashTags.Keys.Intersect(historicalHashTags.Keys).
ToDictionary(x => x, x => currentHashTags[x]);
But, I want the result to be stored in a list that includes Key, currentHashTags[x], and historicalHashTags[x]
Example:
Dictionary<string, int> currentHashTags =
{ ["#hashtag1", 100], ["#hashtag2", 77], ["#hashtag3", 150], ...}
Dictionary<string, int> historicalHashTags =
{ ["#hashtag1", 144], ["#hashtag4", 66], ["#hashtag5", 150], ...}
List<(string,int,int)> result = { ["#hashtag1", 100, 144] }
To keep only the elements common to both dictionaries, you can use the Intersect method of type Dictionary on their keys. Then with Select method you transform this result into an IEnumerable<(string, int, int)>. Finally convert it to a list.
Dictionary<string, int> currentHashTags = new()
{
{"#hashtag1", 11},
{"#hashtag2", 12},
{"#hashtag3", 13},
{"#hashtag4", 14}
};
Dictionary<string, int> historicalHashTags = new()
{
{"#hashtag2", 22},
{"#hashtag3", 23},
{"#hashtag4", 24},
{"#hashtag5", 25}
};
List<(string, int, int)> intersectedHashTags = currentHashTags.Keys
.Intersect(historicalHashTags.Keys)
.Select(key => (key, currentHashTags[key], historicalHashTags[key]))
.ToList();
// Content of intersectedHashTags:
// ("#hashtag2", 12, 22)
// ("#hashtag3", 13, 23)
// ("#hashtag4", 14, 24)
Assuming your dictionaries are of type Dictionary<string, string> and you want Dictionary<string, List<string>> as output, then this works:
Dictionary<string, List<string>> combinedHashTags =
currentHashTags
.Concat(historicalHashTags)
.GroupBy(x => x.Key, x => x.Value)
.ToDictionary(x => x.Key, x => x.ToList());
To get the intersection a simple join would work:
List<(string Key, int current, int historical)> combined =
(
from c in currentHashTags
join h in historicalHashTags on c.Key equals h.Key
select (c.Key, c.Value, h.Value)
).ToList();

Get Except of multiple nested dictionaries using LINQ expression

I want to get different of n numbers of dictionaries using a lambda expression:
Dictionary<string, string> d1 = new Dictionary<string, string>();
d1.Add("Joe", "2, Barfield Way");
d1.Add("Mike", "17, Apollo Avenue");
d1.Add("Jane", "69, Lance Drive");
Dictionary<string, string> d2 = new Dictionary<string, string>();
d2.Add("Joe", "2, Barfield Way");
d2.Add("Jane", "69, Lance Drive");
// var diff = d1.Except(d2);
Let say I want to get the difference of two above dictionaries var diff = d1.Except(d2);
Now I want to get the same out using lambda expression for N numbers of dictionaries.
For an instant, I have merged two dictionaries into one. I want to get a difference of two dictionaries using lambda expression or any other LINQ expression.
Dictionary<string, Dictionary<string, string>> d = new Dictionary<string, Dictionary<string, string>>();
d.Add("Test", d1);
d.Add("Test2", d2);
I have tried the expression below but could not get any results.
d.Select(c => c.Value.Except(c.Value))
You need some Linq methods:
var result = d.SelectMany(d => d.Value).GroupBy(c => c.Key)
.Where(c => c.Count() == 1).ToDictionary(t => t.Key, t => t.Select(c => c.Value)
.FirstOrDefault()).ToList();
Convert it to a collection of KeyValuePair<> enumerables and follow the same logic using .Aggregate()
var result = d.Select(x => x.Value.AsEnumerable()).Aggregate((x, y) => x.Except(y));
You can store the Dictionaries in a List<Dictionary<string, string>>.
Then query this collection and group by the keys , filter by count of key to get the unique ones only, then build a new Dictionary :
var d1 = new Dictionary<string, string>
{
{ "Joe", "2, Barfield Way" },
{ "Mike", "17, Apollo Avenue" },
{ "Jane", "69, Lance Drive" }
};
var d2 = new Dictionary<string, string>
{
{ "Joe", "2, Barfield Way" },
{ "foo", "bar" },
{ "Jane", "69, Lance Drive" }
};
var d3 = new Dictionary<string, string>
{
{ "hello", "world" },
{ "foo", "bar" }
};
var dicts = new List<Dictionary<string, string>>
{
d1,
d2,
d3
};
var distinct = dicts.SelectMany(d => d) // Flatten the collection of dictionaries
.GroupBy(d => d.Key) // Group the sequence by key
.Where(d => d.Count() == 1) // Filter the result for unique keys only
.ToDictionary(k => k.Key, v => v.Select(x => x.Value)
.First()); // Materialize the sequence in a Dictionary<string, string>
foreach (var key in distinct.Keys)
{
Console.WriteLine($"{key} -> {distinct[key]}");
}
Output is
Mike -> 17, Apollo Avenue
hello -> world
This way you will get the same result:
Dictionary<string, string> d1 = new Dictionary<string, string>();
d1.Add("Joe", "2, Barfield Way");
d1.Add("Mike", "17, Apollo Avenue");
d1.Add("Jane", "69, Lance Drive");
Dictionary<string, string> d2 = new Dictionary<string, string>();
d2.Add("Joe", "2, Barfield Way");
d2.Add("Jane", "69, Lance Drive");
var diff = d1.Except(d2);
Dictionary<string, Dictionary<string, string>> d = new Dictionary<string, Dictionary<string, string>>();
d.Add("Test", d1);
d.Add("Test2", d2);
var diff1 = d.SelectMany(x => x.Value).GroupBy(x => new { x.Key, x.Value }).Where(x => x.Count() == 1).SelectMany(x => x.AsEnumerable());

How to join two dictionaries?

I have two dictionaries. If the values in dict2 are same then we have to add the values for the matching keys from dict1 and generate a result in the result dictionary as given below.
**dict1** **dict2**
Id value Id value
24379 348 24379 270451
24368 348 24368 270451
24377 90 24377 270450
24366 90 24366 270450
24369 10 24369 270450
24300 25
Result:
24379 696
24368 696
24377 190
24366 190
24369 190
I have the following logic and would like to optimize this solution:
Dictionary<int, int> result = new Dictionary<int, int>();
foreach (int itemKey in dict1.keys)
{
result.add (itemKey, dict1.Where(a => dict2.ContainsKey(a.key)
&& dict2.ContiansKey(itemKey)
&& dict2[a.key] == dict2[itemKey])
.Sum(a => a.value);
}
You can do it in two steps:
Prepare a dictionary for looking up the value by dict2's value
Walk through dict1, and insert values from the look-up dictionary
Here is how you can do it:
var lookup = dict1
.Where(p => dict2.ContainsKey(p.Key))
.GroupBy(p => dict2[p.Key])
.ToDictionary(g => g.Key, g => g.Sum(p => p.Value));
var res = dict1.Keys
.Where(k => dict2.ContainsKey(k))
.ToDictionary(k => k, k => lookup[dict2[k]]);
Demo.
public static void DicAddTest()
{
Dictionary<int, int> dic1 = new Dictionary<int, int>() { {24379,348}, { 24368, 348 }, { 24377, 90 }, { 24366, 90 } };
Dictionary<int, int> dic2 = new Dictionary<int, int>() { { 24379, 270451 }, { 24368, 270451 }, { 24377, 270450 }, { 24366, 270450 } };
Dictionary<int, int> dicResult = DicAdd(dic1, dic2);
foreach (KeyValuePair<int, int> kvp in dicResult)
Debug.WriteLine("{0} {1}", kvp.Key, kvp.Value);
Debug.WriteLine("");
}
public static Dictionary<int, int> DicAdd(Dictionary<int, int> dic1, Dictionary<int, int> dic2)
{
Dictionary<int, int> dicResult = new Dictionary<int, int>(dic1);
foreach (int k in dic1.Keys.Where(x => dic2.Keys.Contains(x)))
dicResult[k] = dicResult[k] + dicResult[k];
return dicResult;
}
question is not clear
public static Dictionary<int, int> DicAdd2(Dictionary<int, int> dic1, Dictionary<int, int> dic2)
{
Dictionary<int, int> dicResult = new Dictionary<int, int>();
foreach (KeyValuePair<int, int> kvp in dic1.Where(x => dic2.Keys.Contains(x.Key)))
dicResult.Add(kvp.Key, 2 * kvp.Value);
return dicResult;
}
Perhaps it's easier to do like this, if you are not sure that dict1 and dict2 will have the same keys:
var result = new Dictionary<int, int>();
foreach(var kvp in dict1)
{
int value;
if(dict2.TryGetValue(kvp.Key, out value))
{
result[kvp.Key] = kvp.Value * 2;
}
}
This will only add values present in both dictionaries. If your Dictionary is very big, you could perhaps use a Parallel For, or consider use Hashtable instead.

A library like Python's collections.Counter library for C# -> Getting the difference of values between two dictionary objects in C#

This is how I would create a Dictionary in C#.
Dictionary<string, int> d = new Dictionary<string, int>()
{
{"cheese", 2},
{"cakes", 1},
{"milk", 0},
{"humans", -1} // This one's for laughs
};
In Python if you have a dictionary like so:
from collections import Counter
my_first_dict = {
"cheese": 1,
"cakes": 2,
"milk": 3,
}
my_second_dict = {
"cheese": 0,
"cakes": 1,
"milk": 4,
}
print Counter(my_first_dict) - Counter(my_second_dict)
>>> Counter({'cheese': 1, 'cakes': 1})
As you can see, Counter is very useful when comparing dictionary objects.
Is there a library in C#, that will allow me to do something similar to this, or do I have to code it from scratch?
You can join the two dictionaries together and then create a new one based on the given operation with only a few lines of code:
Dictionary<string, int> d1 = new Dictionary<string, int>();
Dictionary<string, int> d2 = new Dictionary<string, int>();
var difference = d1.Join(d2, pair => pair.Key, pair => pair.Key, (a, b) => new
{
Key = a.Key,
Value = a.Value - b.Value,
})
.Where(pair => pair.Value > 0)
.ToDictionary(pair => pair.Key, pair => pair.Value);
There is no system class that you've shown that wraps a dictionary an provides a - operator for them, but you can make your own if you want easily enough:
public class Counter<T> : IEnumerable<KeyValuePair<T, int>>
{
private IEnumerable<KeyValuePair<T, int>> sequence;
public Counter(IEnumerable<KeyValuePair<T, int>> sequence)
{
this.sequence = sequence;
}
public static Counter<T> operator -(Counter<T> first, Counter<T> second)
{
return new Counter<T>(first.Join(second
, pair => pair.Key, pair => pair.Key, (a, b) =>
new KeyValuePair<T, int>(a.Key, a.Value - b.Value))
.Where(pair => pair.Value > 0));
}
public IEnumerator<KeyValuePair<T, int>> GetEnumerator()
{
return sequence.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
There's no built-in functionality like this, but you can use a bit of Linq:
Dictionary<string, int> first = new Dictionary<string, int>()
{
{"cheese", 1},
{"cakes", 2},
{"milk", 3},
};
Dictionary<string, int> second = new Dictionary<string, int>()
{
{"cheese", 0},
{"cakes", 1},
{"milk", 4},
};
var results =
(from x in first
join y in second on x.Key equals y.Key
where x.Value - y.Value > 0
select new { x.Key, Value = x.Value - y.Value })
.ToDictionary(p => p.Key, p => p.Value);
// returns a dictionary like { { "cheese", 1 }, { "cakes", 1 } }

Merging 3 dictionaries into single dictionary

I have the following
Dictionary<string,string> dict1 has 3 items
"A"="1.1"
"B"="2.1"
"C"="3.1"
Dictionary<string,string> dict2 has 3 items
"A"="1.2"
"B"="2.2"
"C"="3.2"
Dictionary<string,string> dict2 has 3 items
"A"="1.3"
"B"="2.3"
"C"="3.3"
I want a final Dict dictFinal which is of type Dictionary<string,string[]>
"A"="1.1,1.2,1.3"
"B"="2.1,2.2,2.3"
"C"="3.1,3.2,3.3"
Given similar keys, provide a collection of all the dictionaries and use SelectMany to handle a dynamic number of array items:
var dictionaries = new[] { dict1, dict2, dict3 };
var result = dictionaries.SelectMany(dict => dict)
.GroupBy(o => o.Key)
.ToDictionary(g => g.Key,
g => g.Select(o => o.Value).ToArray());
The dictionaries type could be a List<T> not necessarily an array as above. The important thing is that you group them together in a collection in order to LINQ over them.
Assuming all 3 dictionaries have the same keys, the following should do the job:
var d1 = new Dictionary<string, string>()
{
{"A", "1.1"},
{"B", "2.1"},
{"C", "3.1"}
};
var d2 = new Dictionary<string, string>()
{
{"A", "1.2"},
{"B", "2.2"},
{"C", "3.2"}
};
var d3 = new Dictionary<string, string>()
{
{"A", "1.3"},
{"B", "2.3"},
{"C", "3.3"}
};
var result = d1.Keys.ToDictionary(k => k, v => new[] {d1[v], d2[v], d3[v]});
Assuming all have the same keys the most straigt forward way is:
Dictionary<string,string[]> result = new Dictionary<string,string[]>();
foreach(var key in dict1.Keys)
{
result[key] = new string[]{dict1[key], dict2[key], dict3[key]};
}

Categories

Resources