[英]Searching for an item in a list that's nested inside another list based on a property value in C# using LINQ?
Is there a way to search for an item in a list that's nested inside another list based on a property value using LINQ?有没有办法使用 LINQ 根据属性值在嵌套在另一个列表中的列表中搜索项目?
Given the follow models below, for a given Order (variable customerOrder
), I want to return the earliest order date ( Date
) where the Day is "Sunday".鉴于下面的模型,对于给定的订单(变量
customerOrder
),我想返回最早的订单日期( Date
),其中 Day 是“Sunday”。
models:楷模:
public class Order
{
public int Id { get; set; }
public List<OrderLine> OrderLines { get; set; }
}
public class OrderLine
{
public string Description { get; set; }
public List<OrderDate> OrderDates { get; set; }
}
public class OrderDate
{
public DateTime Date { get; set; }
public string Day { get; set; }
}
code:代码:
var dates = new List<DateTime>();
foreach(var a in customerOrder.OrderLines)
{
var orderDate = a.OrderDates.Where(x => x.DateTypeId.Equals("Sunday")).FirstOrDefault();
dates.Add(orderDate.ActualDate);
}
dates.OrderBy(d => d.Date);
return dates.FirstOrDefault();
EDIT More elegant query编辑更优雅的查询
You can use Linq to achieve your result.您可以使用 Linq 来实现您的结果。
Here is a query that would closely mimick your code.这是一个与您的代码非常相似的查询。
customerOrder.OrderLines
.Select(ol => ol.OrderDates
.Where(x => x.Day.Equals("Sunday"))
.FirstOrDefault())
.Where(d => d != null)
.OrderBy(d => d.Date)
.FirstOrDefault();
which could be more elegantly rewritten as:可以更优雅地重写为:
customerOrder.OrderLines
.SelectMany(ol => ol.OrderDates)
.OrderBy(d => d.Date)
.FirstOrDefault(d => d.Day == "Sunday");
Here is a Linqpad query with some test data and dump for you to try.这是一个带有一些测试数据和转储的 Linqpad 查询供您尝试。 Simply copy and paste in Linqpad.
只需复制并粘贴到 Linqpad 中。
void Main()
{
var customerOrder = new Order
{
Id = 1,
OrderLines = Enumerable
.Range(0, 10)
.Select(i => new OrderLine
{
Description = $"Line Description {i}",
OrderDates = Enumerable.Range(0, 10)
.Select(j => new OrderDate
{
Date = DateTime.Now.AddDays(i+j),
Day = DateTime.Now.AddDays(i+j).DayOfWeek.ToString()
})
.ToList()
})
.ToList()
}
.Dump();
customerOrder.OrderLines
.SelectMany(ol => ol.OrderDates)
.OrderBy(d => d.Date)
.FirstOrDefault(d => d.Day == "Sunday")
.Dump();
}
// You can define other methods, fields, classes and namespaces here
public class Order
{
public int Id { get; set; }
public List<OrderLine> OrderLines { get; set; }
}
public class OrderLine
{
public string Description { get; set; }
public List<OrderDate> OrderDates { get; set; }
}
public class OrderDate
{
public DateTime Date { get; set; }
public string Day { get; set; }
}
On a side note the OrderDate
class is not necessary.另一方面,
OrderDate
class 不是必需的。 The DateTime
type has a property DayOfWeek
that you can use to test is a Date is a Sunday. DateTime
类型有一个属性DayOfWeek
,您可以使用它来测试 Date 是否为 Sunday。
DayOfWeek
is an enum so you can simply test MyDate.DayOfWeek == DayOfWeek.Sunday
rather than relying on a string
for that purpose. DayOfWeek
是一个枚举,因此您可以简单地测试MyDate.DayOfWeek == DayOfWeek.Sunday
而不是为此目的依赖string
。
First of all your code will not work as intended.首先,您的代码将无法按预期工作。
dates.OrderBy(d => d.Date);
doesn't work: OrderBy
returns an IEnumerable, it doesn't change the original collection.不起作用:
OrderBy
返回一个 IEnumerable,它不会更改原始集合。 You should either use List.Sort
` or do this:您应该使用
List.Sort
` 或这样做:
dates = dates.OrderBy(d => d.Date).ToList()
Secondly, you use FirstOrDefault
: it has an overload that accepts predicate to search with;其次,您使用
FirstOrDefault
:它有一个接受谓词进行搜索的重载; so the Where
call is not needed.所以不需要
Where
调用。 In addition FirstOrDefault will return null
if nothing found.此外,如果没有找到,FirstOrDefault 将返回
null
。 If this is a possible scenario, you should consider checking whether orderDate
is null:如果这是可能的情况,您应该考虑检查
orderDate
是否为 null:
var dates = new List<DateTime>();
foreach(var a in customerOrder.OrderLines)
{
var orderDate = a.OrderDates.FirstOrDefault(x => x.DateTypeId.Equals("Sunday"));
if (orderDate is {})
{
dates.Add(orderDate.ActualDate);
}
}
dates = dates.OrderBy(d => d.Date).ToList();
return dates.FirstOrDefault();
That should work fine.那应该可以正常工作。 But it hard to guess what aspects of behavior of your code samples are intended and what are not.
但是很难猜测代码示例的行为的哪些方面是有意的,哪些不是。 You ask about searching, but say nothing about OrderBy part.
您询问搜索,但对 OrderBy 部分只字未提。 Could you clarify this part, please?
你能澄清一下这部分吗?
Answering the question, if by better
you mean more compact way, you can go with something like this:回答这个问题,如果你的意思是
better
紧凑的方式,你可以用这样的东西 go :
var result = customerOrder.OrderLines
.SelectMany(a => a.OrderDates)
.OrderBy(d => d.Date)
.FirstOrDefault(x => x.DateTypeId.Equals("Sunday"));
return result;
You shouldn't be bothered with better way
now;你现在不应该为
better way
而烦恼; firstly you should start with at least working way
.首先,您应该至少从
working way
开始。 I suggest you to learn how to do these things both using Linq and without using Linq.我建议你学习如何使用 Linq 和不使用 Linq 来做这些事情。
Better is a bit subjective, but you can use the Enumerable.SelectMany
extension method to flatten the OrderDate
instances into one sequence. Better 有点主观,但您可以使用
Enumerable.SelectMany
扩展方法将OrderDate
实例扁平化为一个序列。
Then you can use the Enumerable.Where
extension method to filter the dates that are "Sunday"
.然后,您可以使用
Enumerable.Where
扩展方法来过滤"Sunday"
的日期。
Then you can use the Enumerable.Min
extension method to get the minimum date.然后您可以使用
Enumerable.Min
扩展方法来获取最小日期。
All of this can be chained together into a single statement.所有这些都可以链接到一个语句中。
DateTime earliestSunday = customeOrder
.OrderLines
.SelectMany(ol => ol.OrderDates)
.Where(od => od.Day == "Sunday")
.Min(od => od.Date);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.