C# Dictionary get all keys with same value - c#

I have a Dictionary with Keys and Values. Is it possible to get all Key who has the same Value?
Example 1=456894, 2=548962, 3=548962, 4=654876 and then get the Key 2 and 3 because it has the same value.
Dictionary<int, int> doublechek = new Dictionary<int, int>();

One possible approach:
var result = doublechek
.GroupBy(z => z.Value)
.Where(z => z.Count() > 1)
.SelectMany(z => z)
.Select(z => z.Key)
.ToList();
GroupBy and Count will get only those with duplicates. SelectMany and Key will get the keys of those with duplicates (i.e. 2 and 3).

I would create a new "flipped" dictionary, containing all the unique values from doublecheck as keys, and for each key a list of values containing all the keys from doublecheck that have the referenced value.
Like so:
Dictionary<int, List<int>> flipped = new Dictionary<int, List<int>>();
foreach (var key in doublecheck.Keys)
{
if (!flipped.ContainsKey(doublecheck[key]))
flipped.Add(doublecheck[key], new List<int>());
flipped[doublecheck[key]].Add(key);
}
The dictionary flipped can be used to find all the keys of doublecheck that have the value you are searching.
Update
When using TryGetValue the code looks like this:
Dictionary<int, List<int>> flipped = new Dictionary<int, List<int>>();
foreach (var key in doublecheck.Keys)
{
if (!flipped.TryGetValue(doublecheck[key], out var valueList);
{
valueList = new List<int>();
flipped.Add(doublecheck[key], valueList);
}
valueList.Add(key);
}
return true;

Related

Populate new dictionary from old dictionary

I have a Dictionary<string, int> where the string is a randomized collection of characters and the int is the ASCII sum of that string.
e.g.
["aaaaaaaaab", 971],
["aaaaaaaaba", 971],
["aaaaaaabaa", 971],
["aaaaaabaaa", 971]
I would like to make a new dictionary from the original where the new key is the value from the original, and the new value is the List<string> which would contain all the strings with the key as the ASCII sum.
e.g.
[971, List<string>{ "aaaaaaaaab", "aaaaaaaaba", "aaaaaaabaa", "aaaaaabaaa"}]
How can I achieve this? I cannot wrap my head around the required steps.
Use could GroupBy and ToDictionary
The premise is :
group by the old Value
project to a new dictionary given the values of the GroupBy
which will be the grouped list of KeyValuePair from the original dictionary, that in-turn has the key selected out of it (.Select(y => y.Key)
Example
var newDict = old.GroupBy(x => x.Value)
.ToDictionary(x => x.Key, x => x.Select(y => y.Key)
.ToList());
Additional Resources
Enumerable.GroupBy Method
Groups the elements of a sequence.
Enumerable.ToDictionary Method
Creates a Dictionary<TKey,TValue> from an IEnumerable<T>.
Since values are not unique, you need to group by Value before converting to dictionary:
var inverse = original
.GroupBy(p => p.Value)
.ToDictionary(g => g.Key, g => g.Select(p => p.Key).ToList());
If you wanted to do this without Linq, you could do the following:
foreach(KeyValuePair<string, int> entry in dict) {
if(!dict2.ContainsKey(entry.Value)) {
dict2[entry.Value] = new List<string>();
}
dict2[entry.Value].Add(entry.Key);
}
Assuming you have dict defined as Dictionary<string, int> dict and dict2 defined as Dictionary<int, List<string>> dict2
Here is a complete example for anyone that wants to "wrap their head around" how to do this, without LINQ.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
Dictionary<string,int> origDict = new Dictionary<string,int>{{"tttt",1},{"fttt",1},{"fftt",2}};
var vals = new int[origDict.Count];
origDict.Values.CopyTo(vals,0);
var keys = new string[origDict.Count];
origDict.Keys.CopyTo(keys,0);
Dictionary<int,List<string>> newDict = new Dictionary<int,List<string>>();
for(int i = 0; i < vals.Length; i++){
int val = vals[i];
if(newDict.ContainsKey(val)){
newDict[val].Add(keys[i]);
}else{
newDict[val] = new List<string>();
newDict[val].Add(keys[i]);
}
}
foreach(var key in newDict.Keys){
Console.WriteLine(key);
foreach(var val in newDict[key]){
Console.WriteLine(val);
}
}
}
}
Output:
1
tttt
fttt
2
fftt

Group Dictionary by splitting the Key and create new Dictionary

I have a Dictionary like this:
Dictionary<string, object> properties = new Dictionary<string, object>()
{
{"aa:bb", MyObject1},
{"aa:cc", MyObject2},
{"dd:xx", MyObject3},
{"dd:yy", MyObject4}
};
The key of the dictionary is a string with ':' as delimiter. Now I want do create from that Dictionary a new one:
Dictionary<string, object> ddProperties = new Dictionary<string, object>()
{
{"xx", MyObject3},
{"yy", MyObject4}
};
I'm looking for an elegant way to create the new Dictionary by splitting the key of the original Dictionary. Is that possible with LINQ?
Try:
var ddProperties = properties.ToDictionary
(kvp => kvp.Key.Split(':')[1], kvp => kvp.Value);
If you only need the ones beginning with dd (as can be seen in your sample output), I would do:
var filteredPairs = from kvp in properties
let split = kvp.Key.Split(':')
where split[0] == "dd"
select new { Key = split[1], kvp.Value };
var ddProperties = filteredPairs.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
Do note that there is no protection against duplicates here. If you're expecting duplicate keys after transformation, how would you like to handle them?
note that since each entry is multiple results, use .SelectMany().
As mentioned, ToDictionary builds dictionaries nicely
properties
.SelectMany(kvp => kvp.Key.Split(':')
// Select each item in the split
// to gain access to the original Key Value Pair parameter
.Select(key => new { Key = key, Value = kvp.Value }))
.ToDictionary(
a => a.Key,
a => a.Value);

Merging dictionaries with similar keys but distinct values in C#

Consider the following dictionaries:
Dictionary<string, double> dict1 = new Dictionary<string, double>()
Dictionary<string, double> dict2 = new Dictionary<string, double>()
The two dictionaries have the exact same keys, but the values are different. I would like to merge the two dictionaries the following way: Create a new dictionary with the same keys as dict1 and dict2, and where the value is an array composed of the matching value in dict1, and the matching value in dict2, for each key.
I can easily do that in a loop, but I was hoping there is a more efficient way of doing it.
Any help would be appreciated! Thank you!
This assumes they really do have the same keys:
var merged = dict1.ToDictionary(pair => pair.Key,
pair => new[] { pair.Value, dict2[pair.Key] });
Or to create a Dictionary<string, Tuple<double, double>>
var merged = dict1.ToDictionary(pair => pair.Key,
pair => Tuple.Create(pair.Value, dict2[pair.Key]));
Or using an anonymous type to make it cleaner if you're going to use it inside the same method:
var merged = dict1.ToDictionary(pair => pair.Key,
pair => new { First = pair.Value,
Second = dict2[pair.Key]) });
As noted in comments, these all still loop internally - they won't be more efficient than writing the loop yourself, but it's nicer to read.

Group by on a List And Return Top 1 Row

I have a list acd with key value pair.
var acd = zebra.Where(v => v.Key.StartsWith("alpha"));
KEY, VALUE
alphaABC, TOP323
alphaBCD, BIG456
alphaDEF, TOP323
What i would want is to get only One Key (Any) from multiple keys which have same values.
In this case 1 and 3 have same values.
I would like to get a new list like below:
alphaABC, TOP323
alphaBCD, BIG456
Basically unique Values only. Any Help ?
List<KeyValuePair<string, string>> data = new List<KeyValuePair<string, string>>()
{ new KeyValuePair<string, string>("ABC", "TOP323"),
new KeyValuePair<string, string>("BCD", "BIG456"),
new KeyValuePair<string, string>("DEF", "TOP323") };
var result = (from d in data
group d by d.Value
into g
select new
{
row = g.FirstOrDefault()
}).ToList();
var items = zebra
.Where(v => v.Key.StartsWith("alpha"))
.GroupBy(pair => pair.Value)
.Select(group => group.First())
.ToArray();
foreach(var item in items)
Console.WriteLine("{0}, {1}", item.Key, item.Value);
Use a Dictionary<TKey,TValue>
var dict = new Dictionary<string,string>(zebra.Count);
foreach (KeyValuePair pair in zebra) {
if (!dict.ContainsKey(pair.Value)) {
dict.Add(pair.Value, pair.Key);
}
}
Note that we invert the meaning of key and value here. We use pair.Value as key in the dict, since we want unique values.
As an alternative you could also declare the dictionary as Dictionary<string,KeyValuePair<string,string>> and add like this
dict.Add(pair.Value, pair);

Рow to get 2 to 4 of the object element

I had error from line
Dictionary<int, string> viewBusinesAndCountLeft = grptemp.Take(4).ToDictionary(x => x.Count, x => x.BusinessCategoryName);
error: "The element with the same key has already been added."
How to do this?
var grptemp = (from adsBusines in m_adsRepository.SaleBusinesAds
group adsBusines by adsBusines.BusinessCategory.Name
into grp
select new
{
BusinessCategoryName = grp.Key,
Count = grp.Select(x => x.BusinessCategory.ChildItems.Count()).Distinct().Count()
}).Take(8);
Dictionary<int, string> viewBusinesAndCountLeft = grptemp.Take(4).ToDictionary(x => x.Count, x => x.BusinessCategoryName);
Dictionary<int, string> viewBusinesAndCountRigth = grptemp.Skip(4).Take(4).ToDictionary(x => x.Count, x => x.BusinessCategoryName);
You are using the count as the key for the dictionary which means you will throw that exception whenever you happen to find two categories with the same count.
If I understand what you're trying to do correctly, you should have the 'business category' as the key to the dictionary and the count as the value.
E.g.
Dictionary<string, int> viewBusinesAndCountLeft = grptemp.Take(4).ToDictionary(x => x.BusinessCategoryName, x => x.Count);
Declaring a Dictionary<T,U> means a dictionary with key of type T (in this case, int) - and the key in a dictionary must be unique.
You probably want the key to be the string, and the value to be the count. Try switching your arguments:
Dictionary<string, int> viewBusinesAndCountLeft =
grptemp.Take(4).ToDictionary(x => x.BusinessCategoryName, x => x.Count);

Categories

Resources