我需要了解如何通過具有“包含”和“不包含”條件的復合鍵來過濾串列。
我有一個清單
List<Entity>();
其中物體是一個類
public class Entity
{
int id;
string docNum;
int docVersion;
}
有一個類似的第二個串列。我需要獲取串列中符合以下條件的元素: “獲取第一個串列的元素,其檔案編號與第二個相同,并且檔案的版本在相同的檔案編號中不同”。
我嘗試與以下Contains()內容結合使用Select():
firstList
.Where(x => secondList.Select(y => y.docNum).Contains(x.docNum))
.Where(x => !secondList.Select(y => y.docVersion).Contains(x.docVersion))
但恐怕它沒有考慮到我還需要比較檔案編號的事實。
在我看來,這應該通過GroupBy()or解決ToDictionary(),但我無法解決。
如果可能的話,請展示一個關于標準 linq 元素的解決方案示例,因為我使用NHibernate
uj5u.com熱心網友回復:
您可以使用Any()而不是Select().Contains(). 例如,過濾復合鍵是否存在secondList如下:
.Where(x => !secondList.Any(y => y.docNum == x.docNum && y.docVersion == x.docVersion)
Select().Contains()在這種情況下,這比沒有中間物件構造稍微高效一些。在某些中間物件更復雜的情況下,節省會增加。
我建議你也使用Any()你的第一個條件,給你類似的東西:
firstList
.Where(x => x.Any(y => y.docNum == x.docNum))
.Where(x => !secondList.Any(y => y.docNum == x.docNum && y.docVersion == x.docVersion)
第一個Where()將過濾掉串列中沒有匹配docNum的所有專案,第二個將過濾剩余的專案以洗掉在第二個串列中具有完全復合匹配的專案。
當然,這是非常低效的,因為您必須掃描secondList兩次 - 部分掃描,但仍然是兩次掃描。最好查找以檔案號為鍵的版本號并使用它來進行更有效的過濾:
var lu = secondList.ToLookup(y => y.docNum, y => y.docVersion);
firstList.Where
(
x =>
{
var l = lu[x.docNum];
return l.Any() && !l.Any(v => v == x.docVersion);
}
)
由于ILookup<>經過合理優化,執行過濾器的實際時間大大減少。使用一些非常簡單的(主要是)隨機串列生成具有相當高的沖突,我測驗了針對 1,000,000 個專案的串列過濾 10,000 個專案,看看有什么區別。第一個選項為 49 秒,查找為 1.8 秒。
也就是說,這真的只會在IEnumerable<>. 如果您正在操作IQueryable<>然后堅持Any()和良好的指數。
uj5u.com熱心網友回復:
如果我明白你想要什么,這應該做:
var results = list1
.Where(l1 => list2.Select(l2 => l2.DocNum).Contains(l1.DocNum))
.GroupJoin(list2, l1 => l1.DocNum, l2 => l2.DocNum, (e, c) => new KeyValuePair<string, IEnumerable<Entity>>(e.DocNum, c.Prepend(e)))
.ToArray();
要么
var results = list1
.GroupJoin(list2, l1 => l1.DocNum, l2 => l2.DocNum, (e, c) => new KeyValuePair<string, IEnumerable<Entity>>(e.DocNum, c.Prepend(e)))
.Where(x => x.Value.Count() > 1)
.ToArray();
然后您可以進一步選擇從結果組中獲取您需要的物體,也許是獲取版本最大的物體,或者全部...
不幸的是,我從未使用過NHibernate,所以我不確定這是否受支持,也許您需要先從資料庫中選擇兩個串列,列舉它們,然后在軟體端執行此操作...
uj5u.com熱心網友回復:
根據您的要求,這可能更容易使用 LINQ 查詢語法,您所做的方式和我發布的解決方案仍然是 LINQ,只是不同的方式。
List<Entity> firstList = new List<Entity>
{
new Entity
{
id = 1,
docNum = "two",
docVersion = 3
},
new Entity
{
id = 2,
docNum = "four",
docVersion = 4
},
new Entity
{
id = 3,
docNum = "ten",
docVersion = 6
}
};
List<Entity> ListTwo = new List<Entity>
{
new Entity
{
id = 1,
docNum = "two",
docVersion = 5
},
new Entity
{
id = 2,
docNum = "eight",
docVersion = 7
},
new Entity
{
id = 3,
docNum = "ten",
docVersion = 5
}
};
var resultList = from list in firstList
from list2 in ListTwo
where list.docNum == list2.docNum
where list.docVersion != list2.docVersion
select list;
首先,我們創建了兩個串列,我們將從中創建結果串列。這些是
firstList和ListTwo然后宣告 a
var并將我們的 LINQ 查詢的結果分配給它from list in firstList from list2 in ListTwo用于選擇我們的兩個資料存盤,我們給出一個名稱來參考這些資料存盤中的單個元素,list并且list2where list.docNum == list2.docNum where list.docVersion != list2.docVersion用于滿足我們的條件。第一個 where 子句檢查docNuminlist是否list2匹配。然后,第二個 where 子句檢查以確保docVersioninlist1和 `list2``` 不相等。select list用于選擇與我們的 where 子句匹配的專案。編輯如果您需要從兩個來源匹配的物體更改select list為select new {list,list2}
如果您要除錯此代碼,您將看到它resultList有兩個值(見圖)。

轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/427892.html
