tags:

views:

28

answers:

2

Hello – I’m trying to get a where condition to apply to a sub collection. I can get the criteria to return the proper parents. However, I want the sub collection to be limited to the criteria as well.

In my example code, I only want people with “LINK” skills; also, I only want the skills for each person to equal “LINK.” That is, each person should only have “LINK” for their skills.

Thanks in advance.

List<Skill> skills = new List<Skill>();
skills.Add(new Skill(){SkillName="ASP.NET"});
skills.Add(new Skill(){SkillName="C#"});
Person p1 = new Person(){ Name="Me", Skills=skills} ;

List<Skill> skills2 = new List<Skill>();
skills2.Add(new Skill(){SkillName="ASP.NET"});
skills2.Add(new Skill(){SkillName="C#"});
skills2.Add(new Skill(){SkillName="LINQ"});
Person p2 = new Person(){ Name="You", Skills=skills2} ;

List<Person> People = new List<Person>();
People.Add(p1);
People.Add(p2);

var oResult = (from item in People
    from sk in item.Skills
    where sk.SkillName == "LINQ" 
    select item 
    ).ToList();

When I run this. I get p2 (correct), but I want the skills of P2 to only equal LINQ

+1  A: 

Do this:

var oResult = (from item in People
                where item.Skills.Count() == 1 &&
                item.Skills.Any(s => s.SkillName == "LINQ")
                select item
    ).ToList();

This query will return nothing because p2 (You) has other skills in addition to LINQ.

You can do what you want this way:

foreach (var person in oResult)
{
    person.Skills.RemoveAll(s => !s.SkillName.Equals("LINQ"));
}

Note: while using LINQ you're only filtering your data. To post process it you use something like the foreach I show you above.

Leniel Macaferi
Thanks Leniel - Actually, I need p2, but I want p2 only with skills LINK. Before: P2 Skills = ASP.NET, C#, LINQAfter: P2 Skills = LINQSorry I was not clear. And thanks again for offering your help with this.
shxo
I did not understand your question. So you want to filter out people with LINQ skill and after sorting you want to remove the other skills maintaining only LINQ for that person. Am I right?
Leniel Macaferi
Yes. That is correct : "remove the other skills maintaining only LINQ for that person"
shxo
I'll prepare a solution. Sit tight.
Leniel Macaferi
Ok Thanks again
shxo
The RemoveAll works. Thanks. I was trying to replicate something like an Inner Join.
shxo
A: 

Try this:

var oResult = (from item in People
               where item.Skills != null
               where item.Skills.Count() > 0
               where item.Skills.All(s => s.SkillName == "LINQ")
               select item
              ).ToList();

Even though your example shows that the Skills collection has a value, you want to make sure that your code doesn't blow up if the Skills property is null.

Also, the All predicate returns true if your list is empty so you need to ensure that it is not empty. The above query reads better, but depending on the implementation of the Skills property calling Count() may cause the entire collection to be iterated. You could use Any() instead to ensure that the collection is not empty.

var oResult = (from item in People
               where item.Skills != null
               where item.Skills.Any()
               where item.Skills.All(s => s.SkillName == "LINQ")
               select item
              ).ToList();
Enigmativity