使用 Linq 根据条件过滤对象列表
Posted
技术标签:
【中文标题】使用 Linq 根据条件过滤对象列表【英文标题】:Using Linq to Filter a List of Objects based on a Condition 【发布时间】: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 => x.Region.Where(t => t.RegionName == region)).ToList();
但是,我收到的返回类型不匹配。如何访问 RegionData 模型并仅选择我想要的区域项(基于区域标识符)?
【问题讨论】:
var filteredData = data.Where(t => t.Region.RegionName == region);var filtered = data.Where(x => x.Region.Any(t => t.RegionName == region));
这不起作用,因为 t.Region 是一个 List 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
(单数名词)至少有Date
和Region
的属性。
区域是RegionDatas
的可枚举序列。每个 RegionData 都有几个属性,其中一个属性RegionName
。
我认为您已经描述了以下要求:
要求:给定
regionName
的字符串值和CasesDtos
的序列,给我每个CasesDto
的Date
和RegionData
,其中至少有一个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
,所以我绕过了不匹配。以上是关于使用 Linq 根据条件过滤对象列表的主要内容,如果未能解决你的问题,请参考以下文章