假设我有两个位置列表。首先是所有可用的位置:
List<Location> locations = new List<Location> {
new Location { id = 1, address = "1 Main St.", selected = false },
...
}
另一个是 my 位置的列表或数组:
List<int> myLocations = new List<int> { 1, 5, 8 };
(ID是不可预测的,但我的位置保证是所有位置的子集。)
我希望外联接两个列表,并使用selected = true
获取位置where locations.id eq myLocation
的结果。
如果我使用Join()或Zip(),那么我得到内连接,换句话说,我丢失了myLocations中不存在的元素,如果我使用以下内容 -
var result = from loc in locations
join my in myLocations
on loc.id equals my into myloc
from m in myloc.DefaultIfEmpty()
select new Location {
id = loc.id, address = loc.address, selected = true
};
然后所有位置都标记为已选中;更不用说它看起来过于复杂。 有没有办法在不循环列表元素的情况下做我想做的事情?
答案 0 :(得分:2)
因为您需要为已经在内存中的每个selected
设置location
属性,所以您可以使用ForEach
扩展方法,如下面的代码:
locations.ForEach(location => location.selected = myLocations
.Any(id => id == location.id)
);
使用此代码,您不会在内存中创建Location
的新实例,就像使用投影(select new Location
)一样。使用locations
中的相同实例。
答案 1 :(得分:1)
根据您的陈述
我的位置保证是所有位置的子集
您可以实施LEFT JOIN
而不是OUTER JOIN
。
尝试以下
locations.Select(l => new Location
{
id = l.id,
adress = l.adress,
selected = myLocations.Any(ml => ml == l.id)
})
答案 2 :(得分:1)
你是如此亲密。
在上一个查询中,您实际实现了所谓的左外连接,但更适合此方案的是group join。
由于LINQ中的左外连接实际上是通过 group join 实现的,所以您只需删除该行
from m in myloc.DefaultIfEmpty()
并像这样使用selected = myloc.Any()
var result = from loc in locations
join my in myLocations
on loc.id equals my into myloc
select new Location {
id = loc.id, address = loc.address, selected = myloc.Any()
};
答案 3 :(得分:0)
CodeNotFound的答案是有效的,如果可以修改原始位置对象。
如果您需要的东西纯粹作为没有副作用的查询(通常更符合Linq的精神),那么以下内容将起作用。 这类似于tchelidze的回答,但避免创建所有不匹配的对象的新实例:
locations.Select(l => myLocations.Any(i => i == l.id) ?
new Location {id = l.id, address = l.address, selected = true } : l);
或使用查询语法:
from location in locations
select myLocations.Any(i => i == location.id)
? new Location {
id = location.id,
address = location.address,
selected = true }
: location;