鉴于以下两个类:
public class Apple
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Worm
{
public int AppleId { get; set; }
public int WormType { get; set; }
public int HungerValue { get; set; }
}
所有蠕虫实例的AppleId等于随机存在的Apple.Id
public void DoLINQ(List<Apple> apples, List<Worm> worms, string targetAppleName, List<int> wormTypes )
{
// Write LINQ Query here
}
我们如何编写Linq查询 找到&#39; apples&#39;中的所有元素,其名称&#39;匹配&#39; targetAppleName&#39; 和 (不是&#34;包含&#34; Wormtypes中给出的蠕虫类型的任何蠕虫 要么 只包含Hungervalue等于500的蠕虫?
请注意,Apple的实例实际上并不包含&#39;蠕虫的任何元素,因为这种关系是相反的。这也是使事情变得复杂的原因以及为什么更难以弄明白。
- 更新1 -
我尝试选择具有相同Id的多个苹果:
var query =
from a in apples
join w in worms
on a.Id equals w.AppleId
where (a.Name == targetAppleName) && (!wormTypes.Any(p => p == w.WormType) || w.HungerValue == 500)
select a;
- 更新2 -
这更接近解决方案。这里我们使用两个查询然后合并结果:
var query =
from a in apples
join w in worms
on a.Id equals w.AppleId
where (a.Name == targetAppleName) && !wormTypes.Any(p => p == w.WormType)
group a by a.Id into q
select q;
var query2 =
from a in apples
join w in worms
on a.Id equals w.AppleId
where (a.Name == targetAppleName) && wormTypes.Any(p => p == w.WormType) && w.HungerValue == 500
group a by a.Id into q
select q;
var merged = query.Concat(query2).Distinct();
- 更新3-- 对于输入,我们希望LINQ查询使用方法中的参数,仅使用那些参数。 对于输出,我们想要所有满足上述条件的苹果。
答案 0 :(得分:1)
var result = apples.Where(apple =>
{
var wormsInApple = worms.Where(worm => worm.AppleId == apple.Id);
return apple.Name == targetAppleName
&& (wormsInApple.Any(worm => wormTypes.Contains(worm.WormType)) == false
|| wormsInApple.All(worm => worm.HungerValue == 500));
});
对于每个苹果,在该苹果中创建一系列蠕虫。只返回符合所需名称 AND 的苹果(不包含WormType中的蠕虫 OR 仅包含HungerValue为500的蠕虫)。
答案 1 :(得分:1)
如果要使用查询语法,可以使用let结构查找给定苹果的蠕虫:
var q =
from a in apples
let ws = from w in worms where w.AppleId == a.Id select w
where
(ws.All(w => w.HungerValue == 500)
|| ws.All(w => !wormTypes.Any(wt => wt == w.WormType)))
&& a.Name == targetAppleName
select a;
在方法链语法中,这相当于使用Select:
引入中间匿名对象var q =
apples.Select(a => new {a, ws = worms.Where(w => w.AppleId == a.Id)})
.Where(t => (t.ws.All(w => w.HungerValue == 500)
|| t.ws.All(w => wormTypes.All(wt => wt != w.WormType)))
&& t.a.Name == targetAppleName).Select(t => t.a);
我不会完全称之为可读性: - )
答案 2 :(得分:0)
使用lambda看起来像这样:
var result = apples.Where(a =>
a.Name == targetAppleName &&
(worms.Any(w => w.AppleId == a.Id && w.HungerValue >= 500)) ||
worms.All(w => w.AppleId != a.Id));
我认为lambda使代码看起来更清洁/更容易阅读,而且.Any()
和.All()
的使用效率比加入IMHO时更加有效...我还没有'用任何重要的数据对它进行测试,这里很难说出权威(加上,不会有那么多苹果......!)
public class Apple { public int Id { get; set; } public string Name { get; set; } } public class Worm { public int AppleId { get; set; } public int WormType { get; set; } public int HungerValue { get; set; } } void Main() { var apples = Enumerable.Range(1, 9).Select(e => new Apple { Id = e, Name = "Apple_" + e}).ToList(); var worms = Enumerable.Range(1, 9).SelectMany(a => Enumerable.Range(1, 5).Select((e, i) => new Worm { AppleId = a, WormType = e, HungerValue = i %2 == 0 ? a * e * 20 : 100 })).ToList(); DoLINQ(apples, worms, "Apple_4", new[] {4, 5}); } public void DoLINQ(IList apples, IList worms, string targetAppleName, IList wormTypes) { // Write LINQ Query here var result = apples.Where(a => a.Name == targetAppleName && (worms.All(w => w.AppleId != a.Id) || worms.Any(w => w.AppleId == a.Id && w.HungerValue >= 500))); result.Dump(); // remark this out if you're not using LINQPad apples.Dump(); // remark this out if you're not using LINQPad worms.Dump(); // remark this out if you're not using LINQPad }
答案 3 :(得分:-2)
我已经修改了您的查询但尚未经过测试但是让我们一起来试试吧。希望它能解决你的问题。
var query =
from a in apples
join w in worms
on a.Id equals w.AppleId into pt
from w in pt.DefaultIfEmpty()
where (a.Name == targetAppleName) && (!wormTypes.Any(p => p == w.WormType) || (w.HungerValue == 500))
select a;
感谢。