Any cool quick ways to take two dictionaries to create a third that maps the key of the first to the value of the second in an inner-join style?
Dictionary<A,B> dic1 = new Dictionary<A,B> {{a1,b1},{a2,b2},{a3,b3}};
Dictionary<B,C> dic2 = new Dictionary<B,C> {{b1,c1},{b2,c2},{b4,c4}};
Dictionary<A,C> dic3 = SomeFunction(dic1,dic2);
// dic3 = {{a1,c1},{a2,c2}}
You could do something like this to join on the inner value
Dictionary<int, string> first = new Dictionary<int, string> { {1, "hello"}, {2, "world"}};
Dictionary<string, bool> second =
new Dictionary<string, bool> { { "hello", true }, {"world", false}};
var result = (from f in first
join s in second on f.Value equals s.Key
select new { f.Key, s.Value }).ToDictionary(x => x.Key, y => y.Value);
If you dump out result you'll see it is a Dictionary with the value {1: true, 2: false}
try this -
Dictionary<string, string> a, b, c;
//code to initialize the 3 dictionaries. a,b are original dictionaries and c is the new dictionary
c = ( from ak in a.Keys
where b.ContainsKey( ak )
select new KeyValuePair<string, string>( ak, b[ ak ] ) ).ToDictionary( d => d.Key, d=> d.Value );
Maybe something with ToDictionary
dic1.Where(d1=>dic2.ContainsKey(d1.Value)).ToDictionary(d1=>d1.Key,d1=>dic2[d1.Value]);
Dictionary<int, string> dic1 = new Dictionary<int,string>();
Dictionary<string, decimal> dic2 = new Dictionary<string,decimal>();
dic1.Add(1, "one");
dic1.Add(2, "two");
dic1.Add(3, "three");
dic1.Add(4, "four");
dic1.Add(5, "five");
dic2.Add("one",1.0m);
dic2.Add("two", 2.0m);
dic2.Add("three", 3.0m);
dic2.Add("four", 4.0m);
dic2.Add("five", 5.0m);
Dictionary<int, decimal> result = (from d1 in dic1
from d2 in dic2
where d1.Value == d2.Key
select new { d1.Key, d2.Value }).ToDictionary(p=>p.Key, p=>p.Value);
public Dictionary<A,C> SomeFunction(dic1, dic2)
{
var dic3 = new Dictionary<A,C>();
foreach (var item in dic1)
{
var item2 = dic2.Where(m=>m.Key == item.Value).FirstOrDefault();
if (item2 != null)
{
dic3.Add(item.Key, item2.Value);
}
}
return dic3
}
I believe this will work for what you want
public IDictionary<A, C> SomeFunction<A, B, C>(IDictionary<A, B> dic1, IDictionary<B, C> dic2)
{
var dic3 = new Dictionary<A, C>();
foreach (var item in dic1)
{
var a = item.Key;
var b = item.Value;
if (dic2.ContainsKey(b))
{
var c = dic2[b];
dic3.Add(a, c);
}
}
return dic3;
}
Handles the case of dic2 not containing keys corresponding to dic1s value without fake null values being stored, and IMO is pretty clear. I do like some LINQ, but I thought I'd give a procedural answer for once...
The simplest solution:
var dict3 = dict1.ToDictionary(p => p.Key, p => dict2[p.Value]);
Related
I am having difficulty combining two dictionaries into a dictionary with two values combined to a list for identical keys. For example, having D1 and D2
D1 = {2:"a",
3:"b",
4: "c"}
D2 = {1:"e",
2:"f",
4:"h",
5:"i"}
I would like to create D3.
D3= { 1:["", "e"]
2:["a", "f"]
3:["b", ""]
4:["c":"h"]
5:["", "i"]}
Thank you.
This can be done in a single Linq expression like so:
Flatten and concatenate both d1 and d2 to a single flat sequence of (Int32,String) value-tuples.
Re-group them by the Int32 key (this is the main step).
Then convert each group into a separate output dictionary entry.
Dictionary<Int32,String> d1 = new Dictionary<Int32,String>()
{
{ 2, "a" },
{ 3, "b" },
{ 4, "c" },
};
Dictionary<Int32,String> d2 = new Dictionary<Int32,String>()
{
{ 1, "e" },
{ 2, "f" },
{ 4, "h" },
{ 5, "i" },
};
Dictionary<Int32,List<String>> d3 = Array
.Empty<( Int32 k, String v )>()
// Step 1:
.Concat( d1.Select( kvp => ( k: kvp.Key, v: kvp.Value ) ) )
.Concat( d2.Select( kvp => ( k: kvp.Key, v: kvp.Value ) ) )
// Step 2:
.GroupBy( t => t.k )
// Step 3:
.ToDictionary(
grp => grp.Key,
grp => grp.Select( t => t.v ).OrderBy( v => v ).ToList()
);
An advantage of this approach is that it works for any number of duplicated values (not just two). Also, the use of ValueTuple means this approach should have fewer heap-allocations.
Screenshot proof of it working in LinqPad:
The expression can be made more succint - I use a more verbose style myself, but if you want to be cryptic about it by re-using KeyValuePair instead of ValueTuple, and if you don't care about ordering, then you can do this:
var d3 = d1
.Concat( d2 )
.GroupBy( kvp => kvp.Key )
.ToDictionary( g => g.Key, g => g.Select( kvp => kvp.Value ).ToList() );
Simplest solution would be with Dictionary.Keys
var D1 = new Dictionary<int,string>(){{2,"a"}, {3,"b"},{4,"c"}};
var D2 = new Dictionary<int,string>(){{1,"e"},{2,"f"}, {4,"h"},{5,"i"}};
var keys = D1.Keys.Union(D2.Keys).OrderBy(key => key);
var test = keys.Select(key => new {Key = key, Value= new string[] {D1.ContainsKey(key) ? D1[key] : "", D2.ContainsKey(key) ? D2[key] : ""} });
Console.WriteLine(test);
Interactive: https://rextester.com/UXQ51844
Alternatively, you could do something similar to this: LINQ - Full Outer Join
Sounds to be a job for LINQ. Here is one possibility to solve this issue:
public class Element
{
public int Index { get; set; }
public string Value { get; set; }
}
public class GroupedElement
{
public int Index { get; set; }
public IReadOnlyList<string> Values { get; set; }
}
public static class Program
{
public static void Main(string[] args)
{
var d1 = new[]
{
new Element { Index = 2, Value = "a" },
new Element { Index = 3, Value = "b" },
new Element { Index = 4, Value = "c" },
};
var d2 = new[]
{
new Element { Index = 1, Value = "e" },
new Element { Index = 2, Value = "f" },
new Element { Index = 4, Value = "h" },
new Element { Index = 5, Value = "i" },
};
var result = d1.Concat(d2)
.GroupBy(element => element.Index)
.Select(group => new GroupedElement { Index = group.Key, Values = group.Select(g => g.Value).ToList() })
.ToList();
foreach (var item in result)
{
Console.WriteLine($"{item.Index}: {string.Join(",", item.Values)}");
}
}
}
I think this is simpler without LINQ (LINQ is a hammer, not every problem is a nail)
Let's loop from 1 to 5, putting a new List for each int. The list is inited with d1's value and d2's value
var d3 = new Dictionary<int, List<string>>();
for(int x=1;x<6;x++)
d3[x] = new() { d1.GetValueOrDefault(x,""), d2.GetValueOrDefault(x,"") };
If your ints aren't always contiguous you could (use a bit of LINQ 😀 and..)
foreach(int x in d1.Keys.Union(d2.Keys))
d3[x] = new() { d1.GetValueOrDefault(x,""), d2.GetValueOrDefault(x,"") };
This doesn't need another answer the others answers are plenty good enough and well done, however here is another (convoluted) approach
Given
var d1 = new Dictionary<int, string> {{2, "a"}, {3, "b"}, {4, "c"}};
var d2 = new Dictionary<int, string> { { 1, "e" }, { 2, "f" }, { 4, "h" }, { 5, "i" } };
Usage
static string[] Stuff((string, string)[] v) =>
new[] {v[0].Item1 ?? v.ElementAtOrDefault(1).Item1 ?? "", v[0].Item2 ?? v.ElementAtOrDefault(1).Item2 ?? "" };
var result = d1
.Select(x => (x.Key, (x.Value,(string)null)))
.Concat(d2.Select(x => (x.Key, ((string)null, x.Value ))))
.GroupBy(element => element.Key)
.ToDictionary(x => x.Key, x => Stuff(x.Select(y =>y.Item2).ToArray()))
Output
foreach (var item in result.OrderBy(x => x.Key))
Console.WriteLine($"{item.Key}: {string.Join(",", item.Value)}");
---
1: ,e
2: a,f
3: b,
4: c,h
5: ,i
Please see, here is another approach for this query -
Input -
Dictionary<int, string> first_dict = new Dictionary<int, string>()
{
{ 2,"a" },
{ 3,"b" },
{ 4, "c"}
};
Dictionary<int, string> second_dict = new Dictionary<int, string>()
{
{ 1,"e" },
{ 2,"f" },
{ 4, "h"},
{ 5, "i"}
};
First, I got common keys from both dictionaries like this -
var allKeys = first_dict.Concat(second_dict).OrderBy(b => b.Key).Select(b => b.Key).Distinct().ToList();
and then I created two another dictionaries and inserted data into them like this -
Dictionary<int, string> first_dict_res = new Dictionary<int, string>();
Dictionary<int, string> second_dict_res = new Dictionary<int, string>();
foreach (var keyItem in allKeys)
{
var first_dict_res_value = (first_dict.ContainsKey(keyItem)) ? first_dict[keyItem] : null;
first_dict_res.Add(keyItem, first_dict_res_value);
var second_dict_res_value = (second_dict.ContainsKey(keyItem)) ? second_dict[keyItem] : null;
second_dict_res.Add(keyItem, second_dict_res_value);
}
and then I concatenated the result from both dictionaries to get the desired result-
var res_dict = first_dict_res.Concat(second_dict_res).GroupBy(b => b.Key)
.Select(c => new { key = c.Key, values = string.Join(",", c.Select(b => b.Value)) }).ToList();
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());
My Dictionary<int, List<MyObject>> result has..
Key Value
1 {"Chicago", 100}
1 {"Newyork", 200}
2 {"Minneapolis", 300}
want to convert it to List<List<string>> in below format.
{"Index", "City","Value"},
{1, "Chicago", 100},
{1, "Newyork", 200}
{2, "Minneapolis", 300}
This is what I have achieved so far
var list = result.Select(rec => new
{
Index = rec.Key,
City = rec.Value.Select(rec1 => rec1.City),
Value = rec.Value.Select(rec1 => rec1.Value)
}).ToList();
What I am getting is this..
{"Index", "City", "Value"},
{1, System.Linq.Enumerable.WhereSelectListIterator<MyObject, string>, System.Linq.Enumerable.WhereSelectListIterator<MyObject, int>},
{1, System.Linq.Enumerable.WhereSelectListIterator<MyObject, string>, System.Linq.Enumerable.WhereSelectListIterator<MyObject, int>},
{2, System.Linq.Enumerable.WhereSelectListIterator<MyObject, string>, System.Linq.Enumerable.WhereSelectListIterator<MyObject, int>}
May be I am missing Where condition. Please suggest.
public class MyObject
{
public MyObject(){}
public string City{get;set;}
public int Value{get;set;}
}
This is what you need:
var Result = result.SelectMany(r => r.Value.Select(x => new[] { r.Key.ToString(), x.City, x.Value.ToString() }.ToList()));
To prepend column names as the first element of the outer list:
Result.Insert(0, {"Index", "City","Value"}.ToList());
Do you need the output like this?
I have a solution for you. Try it.
Dictionary<int, List<MyObject>> result = new Dictionary<int, List<MyObject>>();
result.Add(1, new List<MyObject>() { new MyObject() { City = "Chicago", Value = 100 }, new MyObject() { City = "Newyork", Value = 200 } });
result.Add(2, new List<MyObject>() { new MyObject() { City = "Minneapolis", Value = 300 } });
var resultYouWant = result.SelectMany(p => p.Value.Select(a => new { Index = p.Key, a.City, a.Value })).ToList();
below code is work for you but not getting what is your usecase.
var list = result.Select(rec => new
{
Index = rec.Key,
City = rec.Value.City),
Value = rec.Value.Value)
}).ToList();
City = rec.Value.Select(rec1 => rec1.City),
That is creating an IEnumerable, not a string. Which is why you get System.Linq.Enumerable.WhereSelectListIterator out of it.
You may be better off using for loops here.
foreach(var kvp in result)
foreach(var value in kvp)
//Create string here and add it to your list.
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 } }
Please, help minimize the following code:
There is a class with dictionary property:
class Foo
{
public int Field { get; set; }
public Dictionary<int, bool> dic { get; set; }
}
And a list of Foo instances. I want to get united dictionary from all class instances like that:
...
var items = new List<Foo>
{
new Foo {Field = 1, Dic = new Dictionary<int, bool> {{1, true}, {2, false}}},
new Foo {Field = 2, Dic = new Dictionary<int, bool> {{3, true}, {2, false}}}
};
var result = new Dictionary<int, bool>();
foreach (var dics in items.Select(x => x.Dic))
foreach (var pair in dics)
if (!result.ContainsKey(pair.Key))
result.Add(pair.Key, pair.Value);
// testing output
foreach (var pair in result)
Console.WriteLine("{0}, {1}", pair.Key, pair.Value);
Is it possible to do this with pure LINQ approach?
Thank you in advance!
You can use SelectMany to grab and flatten the inner dictionary elements:
var result = items.SelectMany(f => f.Dic)
.GroupBy(pair => pair.Key)
.ToDictionary(g => g.Key, g => g.First().Value);
edit: If you're feeling brave, this can be improved even further by picking up the DistinctBy method from Jon Skeet's morelinq project. Essentially, the GroupBy step is actually overkill, since all we really want is the first value for each key. If we select only the pairs with distinct keys, we can avoid the grouping and subsequent First call, like so:
var result = items.SelectMany(f => f.Dic)
.DistinctBy(pair => pair.Key)
.ToDictionary(pair => pair.Key, pair => pair.Value);
var result =
(from item in items
from pair in item.Dic
group pair by pair.Key
).ToDictionary(g => g.Key, g => g.First().Value);
I don't know if Distinct is better but it is shorter to write.
var result = items.SelectMany(d => d.Dic)
.Distinct()
.ToDictionary(p => p.Key, p => p.Value);
But I actually kind of like using foreach for this.
var result = new Dictionary<int, bool>();
foreach (var dic in items.SelectMany(d => d.Dic))
result[dic.Key] = dic.Value;