如何用 LINQ 替换嵌套循环 - 以一种干净、可管理的方式
How to replace nested loops with LINQ - in a clean, manageable manner
Codewise,使用 linq 执行此操作的最简洁方法是什么?下面,我有一个粗略的例子,我想根据名称找到一个匹配的 class 实例。
class item
{
string name {get;set;}
int identifier {get;set;}
}
void DoSomething()
{
List<item> List1 = GetSampleItems();
List<item> List2 = GetOtherSampleItems();
for(int a=0;a<List1.count;a++)
{
for(int b=0;b<List2.count;b++)
{
if(List1[a].identifier == List2[b].identifier)
{
List1[a].name = List2[b].name;
}
}
}
}
Linq 用于查询,而不是更新,因此您仍然需要循环遍历结果以进行更改,但是您可以 join
像这样匹配两个列表:
var query = from l1 in List1
join l2 in List2
on l1.identifier equals l2.identifier
select new {l1, l2};
现在循环查询以更新 l1
项:
foreach(var item in query)
item.l1.name = item.l2.name;
附带说明一下,您的操作方式没有任何错误(除了如果找到匹配项,您可以跳出内部循环)。如果您了解它的工作原理并且性能可以接受,则没有令人信服的理由来更改它。
这应该有效:
var query = from l1 in List1
join l2 in List2 on l1.identifier equals l2.identifier
select new
{
l1values = l1,
l2Name = l2.name
};
foreach(var item in query)
item.l1Values.name = item.l2Name;
更好的方法是使用 Dictionary<TK,TV>
:
Dictionary<int,item> l2dic = List2.ToDictionary(x => x.identifier);
item itm;
List1.ForEach(x => {
if(l2dic.TryGetValue(x.identifier,out itm)) {
x.name = itm.name;
}
});
或者如@Rawling 所说,使用 foreach
循环代替:
Dictionary<int,item> l2dic = List2.ToDictionary(x => x.identifier);
item itm;
foreach(item x in List1) {
if(l2dic.TryGetValue(x.identifier,out itm)) {
x.name = itm.name;
}
}
Ideone demo(对您的 item
class 稍作修改)。
这平均以线性时间运行,而您的方法以二次时间运行。
然而,假设 标识符是唯一的:同一列表中的两个元素不能具有相同的标识符。
结论是变量通常以小写字母开头,因此 list1
和 list2
而 classes 和属性以大写字母开头(这个 Item
, Identifier
和 Name
).
Codewise,使用 linq 执行此操作的最简洁方法是什么?下面,我有一个粗略的例子,我想根据名称找到一个匹配的 class 实例。
class item
{
string name {get;set;}
int identifier {get;set;}
}
void DoSomething()
{
List<item> List1 = GetSampleItems();
List<item> List2 = GetOtherSampleItems();
for(int a=0;a<List1.count;a++)
{
for(int b=0;b<List2.count;b++)
{
if(List1[a].identifier == List2[b].identifier)
{
List1[a].name = List2[b].name;
}
}
}
}
Linq 用于查询,而不是更新,因此您仍然需要循环遍历结果以进行更改,但是您可以 join
像这样匹配两个列表:
var query = from l1 in List1
join l2 in List2
on l1.identifier equals l2.identifier
select new {l1, l2};
现在循环查询以更新 l1
项:
foreach(var item in query)
item.l1.name = item.l2.name;
附带说明一下,您的操作方式没有任何错误(除了如果找到匹配项,您可以跳出内部循环)。如果您了解它的工作原理并且性能可以接受,则没有令人信服的理由来更改它。
这应该有效:
var query = from l1 in List1
join l2 in List2 on l1.identifier equals l2.identifier
select new
{
l1values = l1,
l2Name = l2.name
};
foreach(var item in query)
item.l1Values.name = item.l2Name;
更好的方法是使用 Dictionary<TK,TV>
:
Dictionary<int,item> l2dic = List2.ToDictionary(x => x.identifier);
item itm;
List1.ForEach(x => {
if(l2dic.TryGetValue(x.identifier,out itm)) {
x.name = itm.name;
}
});
或者如@Rawling 所说,使用 foreach
循环代替:
Dictionary<int,item> l2dic = List2.ToDictionary(x => x.identifier);
item itm;
foreach(item x in List1) {
if(l2dic.TryGetValue(x.identifier,out itm)) {
x.name = itm.name;
}
}
Ideone demo(对您的 item
class 稍作修改)。
这平均以线性时间运行,而您的方法以二次时间运行。
然而,假设 标识符是唯一的:同一列表中的两个元素不能具有相同的标识符。
结论是变量通常以小写字母开头,因此 list1
和 list2
而 classes 和属性以大写字母开头(这个 Item
, Identifier
和 Name
).