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());
Related
I am trying to converting a Tuple<List<Guid>, string> to Dictionary<Guid, List<string>>. This is what I have so far:
var listOfTuples = GetListOfTuples(); // returns type List<Tuple<List<Guid>, string>>
var transformedDictionary = new Dictionary<Guid, List<string>>();
foreach (var listOfTuple in listOfTuples)
{
foreach (var key in listOfTuple.Item1)
{
if (!transformedDictionary.ContainsKey(key))
transformedDictionary[key] = new List<string> { listOfTuple.Item2 };
else transformedDictionary[key].Add(listOfTuple.Item2);
}
}
Is there a better way of doing this, perhaps using LINQ; SelectMany, Grouping, or toDictionary?
Update: I have tried this, but clearly not working:
listOfTuples.ToList()
.SelectMany(x => x.Item1,(y, z) => new { key = y.Item2, value = z })
.GroupBy(p => p.key)
.ToDictionary(x => x.Key, x => x.Select(m => m.key));
You are close. The problem is with selecting the right key and value
var result = listOfTuples.SelectMany(t => t.Item1.Select(g => (g, str: t.Item2)))
.GroupBy(item => item.g, item => item.str)
.ToDictionary(g => g.Key, g => g.ToList());
The mistake is here (y, z) => new { key = y.Item2, value = z } - you want the key to be the Guid and therefore instead of it being Item2 it should be z which is the Guid. So you can go with the way I wrote it or just
(y, z) => new { key = z, value = y.Item2 }
Also the .ToList() at the beginning is not needed. You say that listOfTuples already returns a list
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 am working on a small project but have run into a performance roadblock.
I have a Dictionary<string, string>()
I have a string[].
Lets say my Dictionary has 50,000 entries, and my string[] has 30,000 entries.
I want to collect the Keys from my Dictionary where the value.ToCharArray().OrderBy(x => x) equals a value.ToCharArray().OrderBy(x => x) of my string[].
I have tried reducing the number of KeyValue pairs I have to look through by comparing the length of my string[] value to the values in the Dictionary, but that has not really gained me any performance.
Does anyone have an ideas how I can improve the performance of this lookup?
Thanks!
To expand the pseudocode:
var stringToLookUp = GetSomeStrings(s.ToString()).Select(x => x).OrderBy(x => x).ToArray();
var aDictionaryOfStringString = GetDictionary(Resources.stringList);
var results = new List<string>();
foreach (var theString in stringToLookUp.Where(aString=> aString.Length > 0))
{
if (theString.Length > 0)
{
var theStringClosure = theString;
var filteredKeyValuePairs = aDictionaryOfStringString.Where(w => w.Value.Length == theStringClosure.Length && !results.Contains(w.Key)).ToArray();
var foundStrings = filteredKeyValuePairs.Where(kv => kv.Value.ToCharArray().OrderBy(c => c).ToArray().SequenceEqual(theStringClosure))
.Select(kv => kv.Key)
.ToArray();
if (foundStrings.Any()) results.AddRange(foundStrings);
}
}
I think principal problem is you iterate over whole dictionary in every single iteration - this is O(N^2). Better build hashset based on your modified key (either from dictionary or from array) and iterate over the second. This is O(N).
// some values
var dictionary = new Dictionary<string, string>();
var fields = new string[]{};
string[] modifiedFields = new string[fields.Length];
for(var i =0; i < fields.Length; i++)
{
modifiedFields[i] = new string(fields[i].ToCharArray().OrderBy(x =>x).ToArray());
}
var set = new HashSet<string>(modifiedFields);
var results = new List<string>();
foreach(var pair in dictionary)
{
string key = new string(pair.Value.ToCharArray().OrderBy(x =>x).ToArray());
if (set.Contains(key))
{
results.Add(pair.Key);
}
}
You can try this
var stringToLookUp = GetSomeStrings(s.ToString()).Select(x => x).OrderBy(x => x).ToArray();
var aDictionaryOfStringString = GetDictionary(Resources.stringList);
var results = aDictionaryOfStringString.Where(kvp => stringToLookUp.Select(s => s.OrderBy(x => x)).Contains(kvp.Value.OrderBy(x => x))).Select(kvp => kvp.Key).ToList();
I have two dictionaries:
Dictionary<DateTime, decimal> d1; and Dictionary<DateTime, decimal> d2;
I want two execute a linq query to select from d1 all elements where d2..ContainsKey(d1.key);
var results = d1.Where(x => d2.ContainsKey(x.Key)).Select(x => x.Value).ToList();
Or create another dictionary from selected data:
var results = d1.Where(x => d2.ContainsKey(x.Key)).ToDictionary(x => x.Key, x => x.Value);
If you want the decimal-values as result:
IEnumerable<decimal> result = d2.Keys.Intersect(d1.Keys).Select(k => d1[k]);
If you want a new dictionary from the intersection:
Dictionary<DateTime, decimal> result = d2.Keys.Intersect(d1.Keys)
.ToDictionary(k => k, k => d1[k]);
from rec in d1 where d2.ContainsKey(rec.key) select d1
Try this:
var values = d1.Where(kvp => d2.ContainsKey(kvp.Key)).Select(kvp => kvp.Value);
d1.Keys.Intersect(d2.Keys).ToDictionary( x => x, x => d1[x]);
or
d1.Keys.Where(k => d2.ContainsKey(k)).ToDictionary( x => x, x => d1[x]);
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;