簡體   English   中英

如何使用 LINQ 比較 2 個列表/字典(查找列表 1 中大於列表 2 中的值)

[英]How to compare 2 lists/dictionaries using LINQ (Find values in list1 that are greater than values in list2)

我經歷了很多 stackoverflow 線程,但我似乎沒有在這個特定案例中找到任何東西。 考慮包含以下值的 2 個字典:

Dictionary<string, List<double>> someValues1 = new Dictionary<string, List<double>>();
Dictionary<string, List<double>> someValues2 = new Dictionary<string, List<double>>();

現在,每個字典中的列表在運行時不斷填充新值,因此在這種情況下,我們只對比較每個列表交叉字典的最后一個值感興趣。
換句話說,我正在嘗試做以下事情:

  • 過濾掉每個字典以僅從每個 List 中提取最后一個值
  • 檢查從 someValues1 中提取的任何值是否大於從 someValues2 中提取的任何值
  • 將批次重塑為一些有用的格式,例如 Tuple<string, double, string, double> 包含來自匹配對的字典信息。

到目前為止,我已經嘗試了以下事情,我相信這是正確的,但是我很難將匹配重組為元組:

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

我希望得到以下比賽:

  • { "A1", 1.23, "C2", 5.63 } // 1.23 < 5.63
  • { "C1", 1.783, "C2", 5.63 } // 1.783 < 5.63

我相信這可以解決您的問題。

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

編輯:正如 Peter Csala 在他的回答中正確指出的那樣,多次調用Last()降低性能。

但是,在這種情況下,我們正在處理List ,調用應該是 O(1),正如我們在源代碼中看到的那樣。

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

正如 Thiago Cordeiro 所建議的那樣, SelectMany可以很方便。

但正如您所見, Last運算符已被多次調用(在WhereSelect子句中),這可能會導致多次迭代。

您可以使用let關鍵字對此進行優化:

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

您還可以利用集合初始化程序輕松地填充您的字典:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM