【问题标题】:Using Linq to Filter a List of Objects based on a Condition使用 Linq 根据条件过滤对象列表
【发布时间】:2021-12-05 09:49:52
【问题描述】:

我正在解决一个问题,即由于区域名称条件,我想从列表List<RegionData> 中删除不需要的对象。 作为条目输入,我收到var data,其中包含List<CasesDto>。一项CasesDto 对应于某个特定日期收到的所有基于地区的数据。

这是我用作示例的两个类:

public class CasesDto
{    
    public DateTime Date {get; set;}

    public List<RegionData> Region {get; set;}
}

public class RegionData
{
    public string RegionName {get; set;}

    public int DailyActiveCases {get; set;}

    public int DeceasedToDate {get; set;}
}

这是当前的输出示例(为了便于查看,我只包含了两个日期(= 两个 CasesDto)),其中 region 没有 被考虑在内:

[
    {
        "date": "2021-05-22T00:00:00",
        "region": [
            {
                "regionName": "ce",
                "dailyActiveCases": 615,
                "deceasedToDate": 568
            },
            {
                "regionName": "kk",
                "dailyActiveCases": 170,
                "deceasedToDate": 197
            },
            {
                "regionName": "kp",
                "dailyActiveCases": 278,
                "deceasedToDate": 166
            }
        ]
    },
    {
        "date": "2021-05-23T00:00:00",
        "region": [
            {
                "regionName": "ce",
                "dailyActiveCases": 613,
                "deceasedToDate": 570
            },
            {
                "regionName": "kk",
                "dailyActiveCases": 167,
                "deceasedToDate": 197
            },
            {
                "regionName": "kp",
                "dailyActiveCases": 277,
                "deceasedToDate": 166
            }
        ]
    }
]

如果应用 regionName="ce",这是我想要的输出:

[
    {
        "date": "2021-05-22T00:00:00",
        "region": [
            {
                "regionName": "ce",
                "dailyActiveCases": 615,
                "deceasedToDate": 568
            }
        ]
    },
    {
        "date": "2021-05-23T00:00:00",
        "region": [
            {
                "regionName": "ce",
                "dailyActiveCases": 613,
                "deceasedToDate": 570
            }
        ]
    }
]

我想用 lambda 函数解决这个问题。

我的尝试:

data = data.ForEach(x =&gt; x.Region.Where(t =&gt; t.RegionName == region)).ToList();

但是,我收到的返回类型不匹配。如何访问 RegionData 模型并仅选择我想要的区域项(基于区域标识符)?

【问题讨论】:

  • var filteredData = data.Where(t => t.Region.RegionName == region);
  • var filtered = data.Where(x =&gt; x.Region.Any(t =&gt; t.RegionName == region));
  • 这不起作用,因为 t.Region 是一个 List。它找不到 RegionName。它可以与 t.Region[i].RegionName 一起使用,但是没有索引“i”可以帮助我们解决这个问题。
  • @JochemVanHespen 您的示例已编译,但它不起作用。它返回与输入相同的输出。它没有过滤。
  • @JochemVanHespen 非常感谢,您在 sn-p 中的回答非常完美。你能发布你的答案以便我批准吗?

标签: c# .net list linq .net-core


【解决方案1】:
    var cases = new List<CasesDto>{
        new CasesDto{
            Date = DateTime.Now,
            Region = new List<RegionData> {
                new RegionData{
                    RegionName = "CE"
                },
                new RegionData{
                    RegionName = "DE"
                }
            }
        },
        new CasesDto{
            Date = DateTime.Now.AddDays(10),
            Region = new List<RegionData> {             
                new RegionData{
                    RegionName = "DE"
                }
            }
        }
    };
    
    
    var filteredCases = new List<CasesDto>();
    var regionName = "CE";
    cases.ForEach(c => {
        if(c.Region.Any(x => x.RegionName == regionName)){
            c.Region = c.Region.Where(x => x.RegionName == regionName).ToList();
            filteredCases.Add(c);
        }
    });

为了节省我一些时间,稍微简化了一些。使用 ForEach 我们枚举列表并检查我们是否有一个具有给定区域名称的区域。如果是这样,我们过滤当前列表以仅包含正确的区域并将此结果附加到新列表中。

【讨论】:

    【解决方案2】:

    所以你有一个CasesDtos(复数名词)的可枚举序列,其中每个CasesDto(单数名词)至少有DateRegion的属性。

    区域是RegionDatas 的可枚举序列。每个 RegionData 都有几个属性,其中一个属性RegionName

    我认为您已经描述了以下要求:

    要求:给定regionName 的字符串值和CasesDtos 的序列,给我每个CasesDtoDateRegionData,其中至少有一个RegionData 的值为属性RegionName 等于regionName

    如果 CasesDto 有两个具有正确 RegionName 的 RegionData,你没有告诉你想要什么:

    string regionName = "CA";
    var casesDto = new CasesDto
    {
         Date = ...
         Region = new List<RegionData>()
         {
              new RegionData()
              {
                  RegionName = "CA",
                  ...
              },
              new RegionData()
              {
                  RegionName = "CA",
                  ...
              }
        }
    }
    

    casesDto 有两个具有匹配 RegionName 的 RegionData。您希望最终结果是什么:只有日期和 RegionData 之一?哪一个?还是您想要所有具有匹配 RegionName 的 RegionData?

    不管怎样,解决办法是:

    string regionName = "CA";
    IEnumerable<CasesDto> casesDtos = ...
    
    // from every CasesDto, make one object, containing the Date, and a property 
    // Region, which contains only those RegionDatas that have a value for property 
    // RegionName that equals regionName
    var result = casesDtos.Select(casesDto => new
    {
        Date = casesDto.Date,
    
        // keep only those Regions that have a matching RegionName:
        Region = casesDto.Region
            .Where(region => region.RegionName == regionName)
            .ToList(),
    }
    
    // From this selection, keep only those object that have at least one Region:
    .Where(casesDto => casesDto.Region.Any());
                 
    

    简而言之:对于 caseDtos 中的每个 CasesDto,创建一个具有两个属性的新对象:CasesDto 的日期,以及一个包含此 CasesDto 的 RegionDatas 的属性 Region,该 RegionDatas 具有匹配的 RegionName。从这个 Select 结果中,只保留那些在列表 Region 中至少有一个元素的对象。

    【讨论】:

    • 您的回答也提供了正确的结果!谢谢!我根据自己的需要做了一些细微的调整,但逻辑是完美的。我在 var result 变量中放入了 new CasesDto 而不仅仅是 new,所以我绕过了不匹配。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-07
    • 1970-01-01
    相关资源
    最近更新 更多