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;
Related
I have duplicate keys with different values and I want to convert it to a dictionary with 1 key and its values.
The next example will explain best what I mean:
var tup = new List<Tuple<int, int>>();
tup.Add(new Tuple<int, int>(1, 1));
tup.Add(new Tuple<int, int>(1, 2));
var dic = new Dictionary<int, List<int>>();
What is an elegant way to convert the tup to dic?
I managed to do this with foreach but would like to write it in LINQ.
foreach (var item in tup)
{
if (dic.ContainsKey(item.Item1))
{
dic[item.Item1].Add(item.Item2);
}
else
{
dic.Add(item.Item1, new List<int> { item.Item2 });
}
}
var list = tup.GroupBy(x => x.Item1)
.ToDictionary(
x => x.Key,
x => x.Select(y => y.Item2).ToList());
First, we group by GroupBy item 1. This should be obvious enough.
Then, we call ToDictionary and pass in a keySelector and an elementSelector. They select the key and value respectively, given an IGrouping<int, Tuple<int, int>>.
For reference, this particular overload of ToDictionary is used.
Alternatively, as Iridium has said in the comments, this works as well:
var list = tup.GroupBy(x => x.Item1, x => x.Item2)
.ToDictionary(x => x.Key, x => x.ToList());
This overload of GroupBy allows you to select 2 things!
You first need to group by the first tuple element in order to find all elements that have the same key in the dictionary. And then just collect the second tuple elements and make a list out of it:
tup.GroupBy(t => t.Item1)
.ToDictionary(g => g.Key, g => g.Select(t => t.Item2).ToList());
You can use GroupBy to resolve this problem, like:
var tup = new List<Tuple<int, int>>();
tup.Add(new Tuple<int, int>(1, 1));
tup.Add(new Tuple<int, int>(1, 2));
var dic = tup
.GroupBy(x => x.Item1)
.ToDictionary(x => x.Key, tuples => tuples.Select(x => x.Item2).ToList());
BTW, in some cases you can use NameValueCollection, but this is not save your target type, for example
var nvc = tup.Aggregate(new NameValueCollection(),
(seed, current) =>
{
seed.Add(current.Item1.ToString(), current.Item2.ToString());
return seed;
});
foreach (var item in nvc)
{
Console.WriteLine($"Key = {item} Value = {nvc[item.ToString()]}");
}
I get a
Dictionary<DateTime,double>()
from different part of an application. This can return a number of dictionaries which is why I store them in a list:
var masterlist = new List<Dictionary<DateTime, double>>();
I would like to combine the dictionaries now where the DateTime key is equal and turn the result into an array object[,] so that each row looks like this:
DateTime, double_d1, double_d2, ... double_dn
where d1, d2, ..., dn is mock code for the dictionaries in the list.
how can I do this please?
You can try this :
Dictionary<DateTime, double[]> preResult = masterlist.SelectMany(s => s).GroupBy(k => k.Key)
.ToDictionary(k => k.Key, v => v.Select(s => s.Value).ToArray());
var result = preResult.Select(s =>
{
var res = new List<object>();
res.Add(s.Key);
res.AddRange(s.Value.Cast<object>());
return res.ToArray();
}).ToArray();
Here is similar solution to #Ksv3n, where the result is the Dictionary of DateTime as key and List of doubles as value:
Dictionary<DateTime, List<double>> masterDic = masterlist
.SelectMany(dic => dic)
.GroupBy(dic => dic.Key)
.ToDictionary(dic => dic.Key, values => values.Select(v => v.Value).ToList());
You can use Dictionary<DateTime, List<double>>. You loop thru the list of dictionary you have and add entries in to this dictionary.
var masterlist = new List<Dictionary<DateTime, double>>();
Dictionary<DateTime, List<double>> dtDoubles = new Dictionary<DateTime, List<double>>();
foreach (var item in masterlist)
{
foreach (var kvPair in item)
{
if (!dtDoubles.ContainsKey(kvPair.Key))
{
dtDoubles.Add(kvPair.Key, new List<double> {kvPair.Value});
}
else
{
dtDoubles[kvPair.Key].Add(kvPair.Value);
}
}
}
How about this:
Dictionary<DateTime, List<double>> result =
masterlist.Select(x => x.AsEnumerable())
.Aggregate((a, b) => a.Concat(b))
.GroupBy(x => x.Key)
.ToDictionary(k => k.Key, v => v.Select(x => x.Value).ToList());
I am trying to loop through two concurrent dictionaries like the code below, however I want to use a lambda expression instead
foreach (var s in sb_eventdata)
{
foreach (var f in final_data)
{
if (s.Value.Car.Equals(f.Value.Car))
{
Console.Writeline("Found!");
}
}
}
var values = sb_eventdata.Where(k => k.Value.Hometeam.Contains( ???? );
I'm really not sure what to pass into contains, I assume another lambda expression but what?
The closest linq expression to your loops would be:
var sb_eventdata = new Dictionary<string, string>{ {"a", "a"}, {"b", "b"}};
var final_data = new Dictionary<string, string>{{"a", "a"}, {"b", "b"}, {"c","c"}};
var result =
// first loop
sb_eventdata.Select(s =>
// second loop
final_data.Where(f => s.Value.Equals(f.Value)))
// flatten results (returns results from the first dictionary)
.SelectMany(x => x);
You can use a linq Intersect function to find like items in a list.
Then display all like items.
var foo = sb_eventdata.Select(o => o.Value.Car).Intersect(final_data.Select(o => o.Value.Car));
foreach (var item in foo)
{
Console.Writeline("Found!");
}
I think your friend is the Join() method.
In "LinqPad style":
void Main()
{
var a = new[] {
new Car("Opel",200),
new Car("Volkswagen",300),
new Car("Audi", 500)
};
var b = new[] {
new Car("Peugeot", 180),
new Car("Seat", 300),
new Car("Volvo", 480)
};
var c = a.Join(b, ak => ak.Value, bk => bk.Value, (ak,bk) => new {A=ak.Name,B=bk.Name,ak.Value});
c.Dump();
}
// Define other methods and classes here
class Car {
public string Name;
public int Value;
public Car (string name, int value) {
Name = name;
Value = value;
}
}
If you just want to know if both dictionary share at least one value, you can use Any:
if(sb_eventdata.Any(s =>
final_data.Any(f => s.Value.Car.Equals(f.Value.Car))))
Console.WriteLine("Found!");
or with Contains:
if(sb_eventdata.Any(s => final_data.ContainsValue(s.Value)))
Console.WriteLine("Found!");
and if you want to count how many of sb_eventdata are in final_data:
sb_eventdata.Where(s => final_data.ContainsValue(s.Value)).Count();
A C# converting a query to dictionary:
public class myClass
{
public int my_id;
public Dictionary<string, Dictionary<string, string[]>> myDict;
}
Dictionary<string, myClass> dataDict;
Dictionary<int, Dictionary<string, myClass>> query = (from happen in dataDict
group happen by happen.Value.my_id into g
select g).ToDictionary( ?? );
I do not know what I should put in ( ?? ).
Any help would be appreciated.
Try this:
var query = (from happen in dataDict
group happen by happen.Value.my_id into g select g)
.ToDictionary(g => g.Key, g => g.ToDictionary(x => x.Key, x => x.Value));
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]);