1

I'm trying to construct a lambda expression that will match elements of one array with a second. Below is a simplified version of this query:

class Program
{
 static void Main(string[] args)
 {
 string[] listOne = new string[] { "test1", "test2", "test3" };
 MyClass[] listTwo = new MyClass[] { new MyClass("test1") };
 string[] newVals = listOne.Where(p => listTwo.Select(e => e.Name).Equals(p)).ToArray();
 //string[] newVals2 = listOne.Intersect(listTwo.Select(t => t.Name)).ToArray();
 }
 class MyClass
 {
 public MyClass(string name)
 {
 Name = name;
 }
 public string Name {get; set;}
 }
}

I would expect newVals to return an array of 1 value, but it's empty. I realise that uncommenting myVals2 would achieve the same result, but the lists of classes differ more fundamentally than shown.

madth3
7,33712 gold badges53 silver badges74 bronze badges
asked Jan 25, 2013 at 16:11
2
  • listTwo.Select(e => e.Name).Equals(p)? I don't think that's doing what you intended... Commented Jan 25, 2013 at 16:13
  • I believe you are trying to do a join. So instead of using the where clause, use a the regualr linq join (it is clearer as to what you are trying to achieve). Commented Jan 25, 2013 at 21:19

5 Answers 5

4

You are using Equals but you should use Contains. You are checking wheter IEnumerable<> is equal to p, but you want to check if IEnumerable<> contains p, so replace:

string[] newVals = listOne.
 Where(p => listTwo.Select(e => e.Name).Equals(p)).
 ToArray();

with

string[] newVals = listOne.
 Where(p => listTwo.Select(e => e.Name).Contains(p)).
 ToArray();
answered Jan 25, 2013 at 16:14
Sign up to request clarification or add additional context in comments.

1 Comment

You want to be careful using this. listTwo will be iterated for each entry in listOne.
2

Try this:

string[] listOne = new string[] { "test1", "test2", "test3" };
 MyClass[] listTwo = new MyClass[] { new MyClass("test1") };
 string[] newVals = listOne
 .Where(p => listTwo.Select(e => e.Name).Contains(p))
 .ToArray();

listTwo.Select(e => e.Name) is a IEnumerable<string>

answered Jan 25, 2013 at 16:14

Comments

2

You probably want to perform a Join on the 2 collections.

var q = 
 listOne
 .Join(
 listTwo,
 l2 => l2,
 l1 => l1.Name,
 (l2, l1) => new { l2, l1, });

You can change the selector (the last parameter) to suit your needs, if it's just values from listOne for example then have (l2, l1) => l1.

The other solutions will work, but maybe not as you would expect.

Using Linq-Objects Contains within a where clause will cause the entire of listTwo to be iterated for each entry in listOne.

answered Jan 25, 2013 at 16:19

Comments

1

How about something like this:

string[] newVals = listOne.Where(p => listTwo.Any(e => e.Name.Contains(p))).ToArray();

or to be more strict use == instead of Contains.

But if you want to obtain the items that are common between the 2 why not just call .Intersect()??

answered Jan 25, 2013 at 16:15

1 Comment

Intersect won't work because the sequences are not of the same type. You need to use Join, which is why this is the best answer.
0

You are trying to perform a join, technically you are better off simplifying your linq statement to use a join. An example is included below.

 static void Main(string[] args)
 {
 string[] listOne = new [] { "test1", "test2", "test3" };
 MyClass[] listTwo = new [] { new MyClass("test1") };
 string[] newVals = (from str1 in listOne
 join str2 in listTwo.Select(e => e.Name) on str1 equals str2
 select str1).ToArray();
 foreach (var newVal in newVals)
 {
 Console.WriteLine(newVal);
 }
 //string[] newVals2 = listOne.Intersect(listTwo.Select(t => t.Name)).ToArray();
 }
 class MyClass
 {
 public MyClass(string name)
 {
 Name = name;
 }
 public string Name { get; set; }
 }
answered Jan 25, 2013 at 16:21

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.