views:

348

answers:

3

I'm trying to find the best approach to filtering a list with C# (3.5) but I can't seem to find any examples that are similar to my situation. I'm open to using lambdas or linq.

The thing that is unique compared to most of the examples that I've found, is that my list items each have child arrays for example...

var employees= new List<Employee>
{
    new Employee{Name = "John",Nicknames="'J','Big J','Big John'"},
    new Employee{Name = "Joshua",Nicknames="'J','Josh','Joshman'"},
}

I'd then like to filter that list something like this...

//using linq
var matchesByNickname =
from worker in employees
where worker.Nicknames.Equals("J")
select worker;

//or lambda
var employees2 = employees
    .Where(e => Nicknames.Exists(n => n.Nickname == "J"))

But of course since Nicknames is itself an array I cannot use .Equals or .Contains etc. What would be the best approach to filtering a list of this type?

UPDATE: In trying to keep my example simple I've misled you a bit. The list items do have true object arrays on them, not strings. My real world example is a list of custom product objects. The product object has a Regions property on it which is a list of Region objects. A product can have none, 1, or more than 1 region. The region object has a name and an id. So what I really want is to filter a list of products, for any product assigned to a certain region.

+3  A: 

In your example, Nickname is not an array as I see it. It's a string. Assuming it's an array of strings, you could:

var employees2 = employees.Where(e => e.Nicknames.Contains(name));

If you want to keep it as is (string), you can try something along the lines of:

var employees2 = employees.Where(e => e.Nicknames.Split(',')
                                                 .Contains("'" + name + "'"));

In both of the cases above, you can replace Where with FindAll and get results back in a List<T> instead of an IEnumerable<T> (List<T>.FindAll has been around since 2.0 but Enumerable.Where is new in 3.5).

Of course, ideally, you'll make it an array or list like the following and use the first method:

var employees = new List<Employee>
{
    new Employee{Name = "John",Nicknames= new [] {"J", "Big J", "Big John"}},
    new Employee{Name = "Joshua",Nicknames = new [] {"J", "Josh", "Joshman"}},
};

UPDATE: Your real world example is not so much different from this sample case. I think you're looking for Any instead of Contains since you are checking a property, not the whole object for equality:

var filteredProducts = products
        .Where(p => p.Regions.Any(r => r.Name == "regionToSearchFor"));
Mehrdad Afshari
Your updated answer using .Any worked perfectly! Thanks :-)
Colorado Rockie
+3  A: 

Direct Solution

What you actually asked for.

var matchesByNickname =
       from worker in employees
       where worker.Nicknames.Split(',').Exists(n => n.Equals("'J'"))
       select worker;

Real Solution

Store nicknames as some sort of list. It's the correct way to do so.

Travis Gockel
You got there before me! If Colorado Rookie wants a list of nicknames, he/she should use a list of nicknames. :-)
Richard J Foster
What's the `Exists` method? You probably meant to say `Contains`.
Mehrdad Afshari
You don't need to split if they all have single quotes around them. You could do Nicknames.IndexOf("'J'") > 0.
Mark
@Mark: First, it should be `>= 0`. Second, there are subtle issues like matching `"''J'','K'"` with `"'J'"` which might not be desired.
Mehrdad Afshari
@Mehrdad I missed the >= . Good catch. I still wouldn't split the string unless you really needed to match multiple nicknames. If you were doing that on a ton of records it would be a waste.
Mark
@Mark: Indeed, the fundamental act of storing a list as a string is a crappy way to deal with problems ;) To be fair, there are subtle issues with `Split` too (like having a comma in the middle of an item). Anyway, ideally, that's not how one would model the problem at all.
Mehrdad Afshari
Thank you guys all for such a quick response! Sorry I misled with the string arrays. Thanks again!
Colorado Rockie
A: 

If you have the single quotes around the nicknames, you could just peek into the string for the single quoted name.

employees.Where(x=>x.Nicknames.IndexOf("'J'") >= 0)

Edit: Forgot single quotes...and >=

Mark