I went through quite a few stackoverflow threads, but I don't seem to find anything on this specific case. Consider 2 dictionaries containing values as it follows:
Dictionary<string, List<double>> someValues1 = new Dictionary<string, List<double>>();
Dictionary<string, List<double>> someValues2 = new Dictionary<string, List<double>>();
Now, the lists in each dictionary keep on filling up with new values at runtime and we are therefore in this case only interested in comparing the last value of each list cross dictionaries.
In other words, I am trying to do the following thing:
I have tried the following thing so far, which I believe is going the right way, but I am having difficulty in restructuring the matches into a Tuple:
Dictionary<string, List<double>> someValues1 = new Dictionary<string, List<double>>();
Dictionary<string, List<double>> someValues2 = new Dictionary<string, List<double>>();
someValues1 .Add("A1", new List<double>() { 0.1, 1.23 });
someValues1 .Add("B1", new List<double>() { 0.1, 24.2 });
someValues1 .Add("C1", new List<double>() { 0.1, 1.783 });
someValues2.Add("A2", new List<double>() { 0.1, 0.1, 0.2 });
someValues2.Add("B2", new List<double>() { 0.1, 1.23 });
someValues2.Add("C2", new List<double>() { 0.1, 0.1, 5.63 });
var result= someValues1
.Select(item => item.Value.Last()) // Select last value from lists in someValues1
.Where(v => someValues2 // Transform (extract matches v < v2)
.Select(item2 => item2.Value.Last()) // Select last value from lists in someValues2
.Any(v2 => v2 > v)).ToList();
I would expect to get the following matches:
I believe this solves your problem.
var result = someValues2
.SelectMany(e2 => someValues1
.Where(e1 => e1.Value.Last() < e2.Value.Last())
.Select(e1 => (e1.Key, e1.Value.Last(), e2.Key, e2.Value.Last())))
.ToList();
EDIT: As properly pointed out by Peter Csala in his answer, making multiple calls to Last()
can degrade performance.
However, in this scenario, where we're dealing with a List
, the call should be O(1) as we can see in the source code.
public static TSource Last<TSource>(this IEnumerable<TSource> source) {
if (source == null) throw Error.ArgumentNull("source");
IList<TSource> list = source as IList<TSource>;
if (list != null) {
int count = list.Count;
if (count > 0) return list[count - 1];
}
else {
using (IEnumerator<TSource> e = source.GetEnumerator()) {
if (e.MoveNext()) {
TSource result;
do {
result = e.Current;
} while (e.MoveNext());
return result;
}
}
}
throw Error.NoElements();
}
https://github.com/Microsoft/referencesource/blob/master/System.Core/System/Linq/Enumerable.cs#L1088
As Thiago Cordeiro has suggested SelectMany
can be handy.
But as you can see the Last
operator has been called multiple times (in the Where
and the Select
clauses) which might result multiple iterations.
You can optimize this by using let
keyword:
var result =
from left in someValues1
let leftKey = left.Key
let leftValue = left.Value.Last()
from right in someValues2
let rightKey = right.Key
let rightValue = right.Value.Last()
where leftValue < rightValue
select (leftKey, leftValue, rightKey, rightValue);
You can also take advantage of the collection initializer to populate your Dictionaries easily:
var someValues1 = new Dictionary<string, List<double>>
{
{ "A1", new List<double> {0.1, 1.23} },
{ "B1", new List<double> {0.1, 24.2} },
{ "C1", new List<double> {0.1, 1.783} }
};
var someValues2 = new Dictionary<string, List<double>>
{
{ "A2", new List<double> {0.1, 0.1, 0.2} },
{ "B2", new List<double> {0.1, 1.23} },
{ "C2", new List<double> {0.1, 0.1, 5.63} }
};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.