Home > OS >  Using Linq to Filter a List of Objects based on a Condition
Using Linq to Filter a List of Objects based on a Condition

Time:10-18

I am solving an issue where I want to remove unwanted objects from a list List<RegionData> as a result of a region name condition. As an entry input I receive var data , which contains a List<CasesDto>. One item CasesDto corresponds to all region-based data received on one particular date.

These are two of my classes that I am using as an example:

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

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

and

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

    public int DailyActiveCases {get; set;}

    public int DeceasedToDate {get; set;}
}

This is the current output example (I only included two dates (= two CasesDto) for easy-to-view purpose) where region is not taken into consideration:

[
    {
        "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
            }
        ]
    }
]

This is the output I would want if regionName="ce" is applied:

[
    {
        "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
            }
        ]
    }
]

I would like to solve this problem with lambda functions.

My attempt:

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

However, I receive a mismatch in return type. How can I access RegionData model and select only a region item (based on region identifier) that I want?

CodePudding user response:

So you have an enumerable sequence of CasesDtos (plural noun), where every CasesDto (singular noun) has at least properties Date and Region.

Region is an enumerable sequence of RegionDatas. Every RegionData has several properties, among which a property RegionName.

I think you've described the following requirement:

Requirement: given a string value for regionName, and a sequence of CasesDtos, give me the Date and the RegionData of every CasesDto that has at least one RegionData with a value for property RegionName that equals regionName.

You didn't tell what you want if a CasesDto has two RegionData with the correct RegionName:

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

casesDto has two RegionDatas with a matching RegionName. What do you want in your end result: only the Date and one of the RegionDatas? which one? Or do you want all RegionDatas with a matching RegionName?

Anyway, the solution is:

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());
             

In words: for every CasesDto in casesDtos, make one new object with two properties: the Date of the CasesDto, and a property Region which contains the RegionDatas of this CasesDto that have a matching RegionName. From this Select result, keep only those object that have at least one element in list Region.

CodePudding user response:

    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);
        }
    });

Somewhat simplified to save me some time. Using ForEach we enumerate over the list and check if we have a region with given regionnames. If so we filter the current list to only contain the correct regions and append this result to a new list.

  • Related