简体   繁体   中英

Check if data contains a value from List of string in LINQ

I am new to LINQ. I just want to ask if it is possible to check if a field contains a value from a list of string. Say I have a list of string as defined below.

 List<String> yearList = new List<string>();

 yearList.Add("2012");
 yearList.Add("2015");

I also have a class Member :

class Member
{
    public string Name {get; set;}
    public int Year {get; set;}
    ...
}

Object data is of a class that implements IEnumerable<Member> :

IEnumerable<Member> data = ... 

So data may be a List<Member> or a Member[] , or anything else that represents an enumerable sequence of Member objects.

Now I want to get the data if the year field is in my list of years yearList .

Or to be more precise:

Requirement : Given an object data, that implements IEnumerable<Member> , and given an object yearList , which implements IEnumerable<string> , where the string is a textual representation of a year, give me all Members in object data that have a value of property Year that has a textual representation that equals at least one of the values in yearList .

For example data is as follows:

Name (string) | Year (int)
    Ralph     |   2012
    Rafael    |   2012
    Bea       |   2014
    Lee       |   2015

and yearList is the sequence of strings {"2012", "2015"}. I am expecting a result like

Name (string) | Year (int)
    Ralph     |   2012
    Rafael    |   2012
    Bea       |   2014
    Lee       |   2015

I tried the following, but that didn't work

 data.where(x => x.year.contains(yearList));   <--- THIS CODE NEEDS TO BE CHANGED

Is that possible in LINQ?

Think how you would do it with loops

You might do:

foreach(var d in data){
    if(yearList.Contains(d.year))
        ...
}

But this is different to what you wrote; what you wrote doesn't really make sense:

//data.where(x => x.year.contains(yearList));

//as a loop
foreach(var d in data){
    if(d.year.Contains(yearList))
        ...
}

"If a single year contains a list of years..."


So, then you're working with things like LINQ Where and Select, think of them as like a loop operating over the list of things, and you provide a mini-method that accepts a single parameter, of whatever is in the collection, and returns something else. LINQ will loop over the collection calling your method once per item, passing in the item. You get to choose what the item is called

This is why it helps to have plural names for collections and singular names as the argument in the mini-method (lambda).

var cars = //list of cars

cars.Where(car => car.Maker == "Ford");

Avoid using bland names like x , because it *doesn't help you keep straight, in your head, what things are. Take a look at this:

var cars = //list of cars
var seekingMakers = new []{"Ford", GM"};

cars.Where(car => seekingMakers.Any(seekingMaker => car.Maker == seekingMaker));

We've named the outer ( car ) and the inner ( seekingMaker ) to help keep them apart and remind us what they are. seekingMaker is a single string in an string array seekingMakers .


So, for your Where you have to return a boolean from your lambda, and that is used to determine whether the item in the list makes it into the output or not

var winners = //your list of people/year

winners.Where(winner => yearList.Contains(winner.Year));

You can't say winner.Year.Contains(yearList) - you could say winner.Year.IsContainedWithin(yearList) - but there's no such thing as IsContainedWithin - it's the other way round: collection.Contains(singular) - not "singular contains collection"


Now, you never said what datatype "Year" was in your list of people - maybe it's a string, in which case it makes sense why you'd have yearList as a string.. but if it's not a string, then I strongly recommend you avoid having it be a different data type, because converting it in place will clutter up your LINQ statement, and also lower performance, because C# will spend a large amount of time converting values over and over again

At any time you want to run a search against some fixed value, match the datatype of the value to the data type of the data being searched:

Do this:

var winners = //your list of people/year with INTEGER years
var years = new[]{ 2012, 2015 };

winners.Where(winner => yearList.Contains(winner.Year));

Not these:

var winners = //your list of people/year with INTEGER years
var years = new[]{ "2012", "2015" };

//don't convert the winner's Year
winners.Where(winner => yearList.Contains(winner.Year.ToString()));

//really don't parse the string years to ints over and over
winners.Where(winner => yearList.Select(stringYear => int.Parse(stringYear)).Contains(winner.Year));

If your data is coming to you as strings, convert it once:

var winners = //your list of people/year with INTEGER years

//pass every item to int.Parse and capture the result to an array you can reuse
var years = stringYearsFromElsewhere.Select(int.Parse).ToArray();

winners.Where(winner => yearList.Contains(winner.Year));

Particularly when working with LINQ, strive to find ways to make the code read like a book..

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM