Allow duplicate keys with ToDictionary() from LINQ query - c#

I need the Key/Value stuff from a Dictionary. What I do not need is that it does not allow duplicate Keys.
Regex template = new Regex(#"\{(?<key>.+?)\}(?<value>[^{}]*)");
IDictionary<string, string> dictionary = template.Matches(MyString)
.Cast<Match>()
.ToDictionary(x => x.Groups["key"].Value, x => x.Groups["value"].Value);
How can I return the Dictionary allowing duplicate keys?

Use the Lookup class:
Regex template = new Regex(#"\{(?<key>.+?)\}(?<value>[^{}]*)");
ILookup<string, string> dictionary = template.Matches(MyString)
.Cast<Match>()
.ToLookup(x => x.Groups["key"].Value, x => x.Groups["value"].Value);
EDIT: If you expect to get a "plain" resultset (e.g. {key1, value1}, {key1, value2}, {key2, value2} instead of {key1, {value1, value2} }, {key2, {value2} }) you could get the result of type IEnumerable<KeyValuePair<string, string>>:
Regex template = new Regex(#"\{(?<key>.+?)\}(?<value>[^{}]*)");
ILookup<string, string> dictionary = template.Matches(MyString)
.Cast<Match>()
.Select(x =>
new KeyValuePair<string, string>(
x.Groups["key"].Value,
x.Groups["value"].Value
)
);

Related

filter items from list of dictionary in c# based on matching key and values

I have list of Dictionary:-
List<Dictionary<string, string>> list = new List<Dictionary<string, string>>();
Dictionary<string, string> dict = new Dictionary<string,string>();
dict.Add("name", "abc");
dict.Add("age", "22");
dict.Add("address", "xyz,aa");
dict.Add("contact", "111");
list.Add(dict);
Dictionary<string, string> dict2 = new Dictionary<string,string>();
dict2 .Add("name", "pqr");
dict2 .Add("age", "25");
dict2 .Add("address", "xxx,bb");
dict2 .Add("contact", "4222");
list.Add(dict2);
Dictionary<string, string> dict3 = new Dictionary<string,string>();
dict3 .Add("name", "aa");
dict3 .Add("age", "24");
dict3 .Add("address", "xxx,aa");
dict3 .Add("contact", "aaa");
list.Add(dict3);
In this list I want to find out those records which address contains 'aa'
You can do it using Where and Any methods
var result = list.Where(d => d.Values.Any(v => v.Contains("aa")));
It returns you a two Dictionary<string, string> instances, containing values with aa inside.
If you need a filtered list for address key and value contains aa, the code below returns you a dictionaries with the such keys
var result = list.Where(d => d.ContainsKey("address") && d["address"].Contains("aa"));
This code returns the flattened sequence of key/value pairs for entire list
var result = list.SelectMany(l => l).Where(kv => kv.Key == "address" && kv.Value.Contains("aa"));
To perform case-insensitive search (as it stated in comments) StringComparison.OrdinalIgnoreCase should be added to Contains method
var result = list.SelectMany(l => l).Where(kv =>
kv.Key == "address" && kv.Value.Contains("Aa", StringComparison.OrdinalIgnoreCase));
This will give you a list of dictionaries where their address contains "aa"
list.Where(x => x["address"].Contains("aa"));
To ignore case-sensitivity
list.Where(x => x["address"].ToLower().Contains("aa"));
And this will give you a flatten list of records including just pair of key,value where key is "address" and value contains "aa"
list.Where(x => x["address"].Contains("aa")).SelectMany(y=>y.Where(item=>item.Key=="address"));

C# LINQ Merge Dictionaries by comparing keys

I have 2 dictionaries as below
Dictionary<string, string> first= new Dictionary<string, string>();
Dictionary<string, string> second = new Dictionary<string, string>();
first.Add("NAME", "NAME");
first.Add("TYPE", "TYPE");
first.Add("REF","REF");
first.Add("NUMBER", "NUMBER");
first.Add("DATE", "DATE");
first.Add("SOURCE", "SOURCE");
second.Add("TYPE", "T1");
second.Add("REF","A1234");
second.Add("NUMBER", "B456");
second.Add("DATE", "D123455");
second.Add("NAME", "NAME");
second.Add("SOURCE", "SOURCE");
How to achieve a resulting dictionary like below
("NAME", "NAME");
("TYPE", "T1");
("REF","A1234");
("NUMBER", "B456");
("DATE", "D123455");
("SOURCE", "SOURCE");
Ideally first and second merged together with the values from second merged onto first and the keys should retain in the order of first dictionary.
Could anyone suggest the best approach to achieve this, Thanks.
var result = first.Union(second)
.GroupBy(x => x.Key)
.Select(x => new { Key = x.Key, Value = x.Last().Value })
.ToDictionary(x => x.Key, x => x.Value);
First you are union both of collections, after that group them by the keys selects the Last().Value for the value and converting it again to Dictionary.
Here Full example

Transform a dictionary to another with a different key type

Given:
class KeyType1{...}
class KeyType2{...}
class ValueType{...}
public KeyType2 Lookup(KeyType1 value)
{
// Returns a unique value of KeyType2 or otherwise, null
}
Is there a neat LINQ way to transform:
IDictionary<KeyType1,ValueType> ==> IDictionary<KeyType2,ValueType>
The following important points:
No 2 values of type KeyType1 map to the same KeyType2
edit It is possible Lookup may return null i.e. the mapping may not be complete. In such cases, these entries should be omitted from the new dictionary
ok, assuming Lookup is a function that returns a reference type that could be null.
b = a
.Select(p => new { Key = Lookup(p.Key), p.Value }))
.Where(p => p.Key != null)
.ToDictionary(p => p.Key, p => p.Value);
You can use Where firstly to filter the source, then use ToDictionary extension specifying the new key and the value:
var dictionary1 = new Dictionary<KeyType1, ValueType>();
var dictionary2 = dictionary1.Where(kv => Lookup(kv.Key) != null)
.ToDictionary(kv => Lookup(kv.Key), kv => kv.Value);
If you want to compute the key for those cases where Lookup is null you can do this:
dictionary1.ToDictionary(kv => Lookup(kv.Key) ?? ComputeNewKey(kv.Key),
kv => kv.Value);
To avoid to need Lookup twice you can firstly create a Dictionary<KeyType1, KeyType2> to map the old keys to the new ones:
IDictionary<KeyType1,KeyType2> keyMap = sourceDictionary.Keys.ToDictionary(key => key, key => Lookup(key));
This keyMap now may contain null values for some source keys. So we filter it with Where and then combine them with the source dictionary to create your new dictionary:
IDictionary<KeyType2,ValueType> target = keyMap.Where(kvp => kvp.Value != null).
ToDictionary(kvp => kvp.Value, sourceDictionary[kvp.Key]);
Dictionary<string, string> StringDict = new Dictionary<string, string>();
Dictionary<int, string> IntDict = new Dictionary<int, string>();
StringDict.ToList().ForEach(D =>
{
IntDict.Add(Convert.ToInt32(D.Key), D.Value);
});

Build a new dictionary with concatenated duplicated keys based on values

How to concatenate and remove duplicates in dictionary like this:
Item1: Key=1, Value=test1
Item2: Key=2, Value=test2
Item3: Key=3, Value=test1
Item4: Key=4, Value=test3
Item5: Key=5, Value=test4
To build a new Dictionary like this:
Item1: Key=1-3, Value=test1
Item2: Key=2, Value=test2
Item4: Key=4, Value=test3
Item5: Key=5, Value=test4
I managed to get the duplicates using this: myDictionary.GroupBy(x => x.Value).Where(x => x.Count() > 1);
But I can't figure the right way to build a new Dictionary from this.
This works for taking all the duplicate items into a new dictionary with a shared key:
var dict = new Dictionary<string, string>
{
{"1", "test1"},
{"2", "test2"},
{"3", "test1"}
};
var groupedKeyMap = dict.GroupBy(x => x.Value)
.Where(x => x.Count() > 1)
.ToDictionary(x => string.Join("-", x.Select(y => y.Key)),
x => x.Key);
If you need both duplicate and non duplicate key value pairs, remove the Where clause:
var groupedKeyMap = dict.GroupBy(x => x.Value)
.ToDictionary(x => string.Join("-", x.Select(y => y.Key)),
x => x.Key);

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);

Categories

Resources