简体   繁体   English

使用 LINQ 根据 C# 中的属性值搜索嵌套在另一个列表中的列表中的项目?

[英]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.

相关问题 在列表内的值上搜索时,C#Linq NULLReferenceException - C# Linq NULLReferenceException when searching on value inside list C#LINQ-根据另一个列表内的子属性返回类型化的过滤列表 - C# LINQ - Return a typed filtered list based on a child property that is inside another list c#如何使用LINQ根据另一个列表中的值获取列表中的值计数 - c# How to get count of value in a List based on value in another List using LINQ 使用Linq检索基于C#的List &lt;&gt;项的索引 - Retrieve index of a List<> item based in C# using Linq 基于if语句在linq列表中返回C#返回值 - C# return value inside linq list based on if statement C#LINQ如何从另一个列表中的一个列表中找到匹配项,并在另一个列表中检查属性 - C# LINQ How to find matching item from one list in another list and check for the property in the other list c#查找LINQ查询返回的列表中的项目,并将其值与列表中的另一项进行比较 - c# find item in list returned by LINQ query and compare its value with another item in list c#搜索列表 <t> 在另一个列表中 <T> - c# Searching List<t> inside another List<T> c#linq列出一项可能具有基于另一项的两个值 - c# linq list one item could have two values based on another item Linq,从对象列表中,根据另一个属性的值创建属性列表 - Linq, from list of objects, create list of properties based on another property's value
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM