compare two dictionaries by key to obtain values of matching keys - c#

I have two dictionaries A and B.
A - (a,b) (c,d) (e,f)
B - (a,p) (c,q) (g,h)
I want to be able to make a new dictionary C which will be as below -
C - (b,p) (d,q)
Is there any way I can do this?
This is what I currently have:
var C= B.Where(d => A.ContainsKey(d.Key)).ToList();

Easy with Linq ;)
var query =
from x in dictionary1
join y in dictionary2 on x.Key equals y.Key
select new { Value1 = x.Value, Value2 = y.Value };
var newDict = query.ToDictionary(item => item.Value1, item => item.Value2);
However it's not the most efficient approach, since it doesn't take advantage of the dictionary's fast lookup. A faster approach would be something like this:
var newDict = new Dictionary<string, string>(); // adjust the key and value types as needed
foreach (var kvp in dictionary1)
{
string value2;
if (dictionary2.TryGetValue(kvp.Key, out value2))
{
newDict.Add(kvp.Value, value2);
}
}

Related

Calculate average in Dictionary <string, List<double>> C#

I need calculate the average of a List into a dictionary, I´m start using this syntax to access to the double List and gets the average but the compiler give an error, I´m new working with dictionarys, how is the correct syntax to access each double List and gets the average?
Here is the example of my code:
Dictionary<string, List<double>> SignalValues =
new Dictionary<string, List<double>>();
var dSignalAvg = SignalValues
.Where(x => x.Key == "Key")
.Average(x => x.Value);
Thank you so much!
If you are sure that the specific key exists in the dictionary then you can simply do:
var dSignalAvg = SignalValues["Key"].Average();
The code above will throw an exception if the dictionary doesn't have a key that equals "Key". If you want to check first, you can use TryGetValue like this:
double dSignalAvg = 0;
if (SignalValues.TryGetValue("Key", out List<double> signalList))
{
dSignalAvg = signalList.Average();
}
Like this?
Given a dictionary like this:
Dictionary<string,List<double>> values = new Dictionary<string,List<double>>();
Getting the average for a specific key is easy:
double avgValue = values
.Where( x => x.Key == "Key")
.Select( x => x.Value.Average() )
.FirstOrDefault()
;
Or, if you want to reduce your dictionary to a dictionary of averages, it's just:
Dictionary<string,double> avgValues = values
.ToDictionary(
x => x.Key ,
x => x.Value.Average()
)
;

Efficient way to create a new list based of the differences in values in 2 dictionaries?

I currently have 2 strings that are formatted as an XML that are later converted into dictionaries for comparison.
So, I have a 2 Dictionary<string, object>, dict1 and dict2, that I need to compare. I need to:
Add the key to a list of strings if the values of these two dictionaries do not match
Add the key of dict2 to the list if dict1 does not contain this key
Currently, I have a simple foreach loop
foreach (string propName in dict2.Keys)
{
string oldDictValue;
string newDicValue = dict1[propName].ToString();
if (dict1.ContainsKey(propName))
{
oldDictValue = dict2[propName].ToString();
if (oldDictValue != newDicValue)
list.Add(propName);
}
else
{
list.Add(propName);
}
}
I would like to a faster solution to this problem if possible?
I don't claim that this is any faster, but it should be on par and it's less code:
List<string> list =
dict2
.Keys
.Where(k => !(dict1.ContainsKey(k) && dict1[k].Equals(dict2[k])))
.ToList();
I did do some testing with this:
List<string> list =
dict2
.Keys
.AsParallel()
.Where(k => !(dict1.ContainsKey(k) && dict1[k].Equals(dict2[k])))
.ToList();
That produced a significantly faster run.
Here's how I produced my test data:
var dict1 = Enumerable.Range(0, 10000000).Select(x => Random.Shared.Next(2000000)).Distinct().ToDictionary(x => x.ToString(), x => (object)Random.Shared.Next(20));
var dict2 = Enumerable.Range(0, 10000000).Select(x => Random.Shared.Next(2000000)).Distinct().ToDictionary(x => x.ToString(), x => (object)Random.Shared.Next(20));
You could make it faster by avoiding to get separately the dict1[propName] and the dict2[propName]. You could get the value along with the key, either by enumerating directly the KeyValuePairs stored in the dictionary, or by calling the TryGetValue method:
foreach (var (key, value2) in dict2)
{
if (!dict1.TryGetValue(key, out var value1)
|| value1.ToString() != value2.ToString())
{
list.Add(key);
}
}

Compare two dictionaries by key and create a new one where keys don’t match

I have two dictionaries of type (string, string). I need to compare these and create a new dictionary where just the Keys don’t match. For example, given these values
Dictionary A
Key Value
=========
A B
C D
Dictionary B
Key Value
=========
A Z
E D
I need to create a new dictionary that would just have a single entry of (E,D)
==== Edit ====
When the compare is done I am just involving the keys, the values are of no interest. The key values are just strings so don't link to other objects. There is no hidden mapping etc. The "Value" only comes into play when I have the resulting dictionary as this is then used in my program. Think of this problem as if the values didn't exist and I was just trying to get a list of keys that are in dictionary "B" but not in "dictionary "A". I am not interested in key "C" as I am just interested in the unique keys that are just in dictionary "B" but not in dictionary "A".
To create a dictionary containing all elements of B, whose keys are not in A:
var C = B.Where(x => !A.ContainsKey(x.Key))
.ToDictionary(x => x.Key, x => x.Value);
In case you want to create a dictionary containing all elements of B, whose values are in A, but whose keys do not match those of the corresponding values of A, you can use this:
var C =
(from a in A
join b in B on a.Value equals b.Value
where a.Key != b.Key
select b)
.ToDictionary(x => x.Key, x => x.Value);
Note however, this will fail if A contains the same value with two or more keys, e.g. (A, B), (C, D), and (F, D). To address that you can do something like this:
var C =
(from a in A
group a by a.Value into g
let a = g.First()
join b in B on a.Value equals b.Value
where a.Key != b.Key
select b)
.ToDictionary(x => x.Key, x => x.Value);
So you only want to add entries that exist in the second dictionary which are not in the first and not vice-versa?
var dictC = dictB.Keys.Except(dictA.Keys)
.ToDictionary(bKey => bKey, bKey => dictB[bKey]);
If you also want the opposite you could use this approach using Concat on an anonymous type:
var dictC = dictB.Keys.Except(dictA.Keys)
.Select(bKey => new{ Key=bKey, Value=dictB[bKey] })
.Concat(dictA.Keys.Except(dictB.Keys)
.Select(aKey => new{ Key=aKey, Value=dictA[aKey] }))
.ToDictionary(kv => kv.Key, kv => kv.Value);
Duplicate keys aren't possible here since the first query looks for keys in dictionary-1 which are not in the other whereas the second query looks for the opposite. So it's safe to use Concat and ToDictionary.
It seems that you want key-value pairs from dictionary B where dictionary A has a different key for that value. In that case, I'd do something like this:
// sample data
Dictionary<string, string> a = new Dictionary<string, string>();
a.Add("A", "B"); a.Add("C", "D");
Dictionary<string, string> b = new Dictionary<string, string>();
b.Add("A", "Z"); b.Add("E", "D");
// first, reverse dictionary A for simplicity
// to quickly get the key for a value
var revA = a.ToDictionary(kv => kv.Value, kv => kv.Key);
// and then compute the result
var result = b.Where(kv => revA.ContainsKey(kv.Value) && revA[kv.Value] != kv.Key)
.ToDictionary(kv => kv.Key, kv => kv.Value);
This of course assumes that we can not have a value mapped from different keys in the same dictionary. That is, that we can not have for instance (A=>B) and (C=>B) in the same dictionary. I think this is implicitly true in your question.

Using LINQ to build a Dictionary from a List of delimited strings

I have a list of strings that look like this:
abc|key1|486997
def|key1|488979
ghi|key2|998788
gkl|key2|998778
olz|key1|045669
How can I use LINQ and ToDictionary to produce a Dictionary<string, List<string>> that looks like
key1 : { abc|key1|486997, def|key1|488979, olz|key1|045669 }
key2 : { ghi|key2|998788, gkl|key2|998778 }
Basically I want to be able to extract the second element as the key use ToDictionary() to create the dictionary in one go-round.
I'm currently doing this ..
var d = new Dictionary<string, List<string>>();
foreach(var l in values)
{
var b = l.Split('|');
var k = b.ElementAtOrDefault(1);
if (!d.ContainsKey(k))
d.Add(k, new List<string>());
d[k].Add(l);
}
I've seen the questions on building dictionaries from a single string of delimited values, but I'm
wondering if there's an elegant way to do this when starting with a list of delimited strings instead.
var list = new []
{
"abc|key1|486997",
"def|key1|488979",
"ghi|key2|998788",
"gkl|key2|998778",
"olz|key1|045669"
};
var dict = list.GroupBy(x => x.Split('|')[1])
.ToDictionary(x => x.Key, x => x.ToList());
You can also transform it to a lookup (that is very similary to a Dictionary<K,IEnumerable<V>>) in one shot:
var lookup = list.ToLookup(x => x.Split('|')[1]);
var data = new[]
{
"abc|key1|486997",
"def|key1|488979",
"ghi|key2|998788",
"gkl|key2|998778",
"olz|key1|045669"
};
var dictionary = data.Select(row => row.Split('|'))
.GroupBy(row => row[1])
.ToDictionary(group => group.Key, group => group);
If your data is guaranteed to be consistent like that, you could do something like this:
var data = new[]
{
"abc|key1|486997",
"def|key1|488979",
"ghi|key2|998788",
"gkl|key2|998778",
"olz|key1|045669"
};
var items = data
.GroupBy(k => k.Split('|')[1])
.ToDictionary(k => k.Key, v => v.ToList());

what is the best way to convert one dictionary to another

i have one dictionary that has entries that looks like this:
dictionary["ABC.123"] = "Test"
dictionary["DEF.123"] = "Test2"
dictionary["EFG.123"] = "Test3"
dictionary["EFG.343"] = "Test3"
dictionary["ABC.456"] = "Test"
and i want to create a new dictionary that looks like this: (basically parse out the beginning string before the "." and create that as the key and use the same value.
dictionary["ABC"] = "Test"
dictionary["DEF"] = "Test2"
dictionary["EFG"] = "Test3"
as you can see: there is always a 1 to 1 mapping between the first part of the key in the first dictionary to the value so there will be no clashes
what is the easiest way using LINQ to convert to create the second dictionary from the first ??
I can loop through each record manually and parse out the new key and create each new record but i figured there was a LINQ way of doing it
var newDict = dictionary.GroupBy(kvp => kvp.Key.Remove(kvp.Key.IndexOf('.')))
.ToDictionary(grp => grp.Key, grp => grp.First().Value);
Although a plain foreach is probably going to be more readable and efficient:
var newDict = new Dictionary<string, string>();
foreach (var kvp in dictionary)
{
newDict[kvp.Key.Remove(kvp.Key.IndexOf('.'))] = kvp.Value;
}
A simple approach is to use the Select method to generate your desired KeyValuePair in conjuntion with ToDictionary
var response = dictionary
.Select(kvp => new KeyValuePair<string, string>(kvp.Key.Remove(kvp.Key.IndexOf('.')), kvp.Value))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
var dict2 = dictionary.GroupBy(x => x.Key.Split('.')[0])
.ToDictionary(g => g.Key, g => g.First().Value);

Categories