views:

107

answers:

4

I have 2 lists. I want to compare every element with every element for both lists using LINQ (versus using say a nested loop). But, the Contains does not meet my needs because I need to do a custom comparison. I would imagine a custom comparer is what I need but not 100% sure.

I do not think this should be too difficult but not sure exactly the tool that I need for this. The 2 lists both contain distinct and different type of objects.

Update:

Sorry, if I wasn't clear. I have 2 lists (or enumerables) I could do something like this:

foreach(item i in list1)
  foreach(otherItemType in List2)
  {
    if ( CompareItem(x) ) do something;
  }

What I want to do is something like this:

var matches = myList1.Where(t => myList2.Something(t) ) 

Where Something is a custom comparer, perhaps I can override the equals comparison? I could use the .Contains but I need to do my own logic for comparison.

Update: I thought of using the IEqualityComparer but this is set to take types of T, T and T, Y. There may be some generic constraints that I could use to solve this problem. I felt this should be easy/simple.

A: 

I had question here a while back that may help you get started.

JSprang
+1  A: 
var matches = myList1.SelectMany(
    t1 => myList2.Where(
        t2 => t2.Something(t1)
    )
);

The inner Where is like your inner foreach loop, and the outer SelectMany joins the results after iterating through as in your outer foreach loop.

You can also make a function to do this for you (untested; can't recall extension syntax):

public static IEnumerable<T2> MultiCompare<T1, T2>(this IEnumerable<T1> first, IEnumerable<T2> second, Func<bool, T1, T2> comparer) {
    return first.SelectMany(
        t1 => second.Where(
            t2 => comparer(t1, t2)
        )
    );
}
strager
@Strager Thanks. Is there anyway to do this that is more clear? This is slightly difficult to read but appears to work.
Curtis White
@Curtis White, Well, you can make a function, as I just posted.
strager
The extension syntax should be `...MultiCompare<T1, T2>(this IEnumerable<T1> first, ...` then `first.SelectMany(...`
Jamiec
@Strager Thanks. Yes, I had thought of an extension. You will get the credits after the min period is expired. Thanks again!
Curtis White
@Jamiec, Thanks.
strager
+1  A: 

If I understand your question correctly, the sample below will do it. Since Any takes a delegate you can define an arbitrary matching comparison between the two elements of the list. If you need all elements to match, use All in place of Any.

[Test]
public void StackOverflow()
{
  var digits = new int[] {1, 2, 4, 9};
  var strings = new string[] {"1", "4", "5", "7"};

  var matches = strings.Where(s => digits.Any(d => d.ToString() == s)).ToList();

  // Prints
  // 1
  // 4

  matches.ForEach(x => System.Diagnostics.Debug.WriteLine(x));
}
Rob
+1  A: 

How about using Enumerable.Join?

var list = new List<int> { 1, 2, 3, 4, 5 };
var list2 = new List<string> { "2", "4", "5" };

var matches = from i in list
              join s in list2 on i.ToString() equals s
              select i; // if you want to use the matching items from the 1st list

// there's no ForEach on Enumerable so you'd have to write the extension yourself (which is easy)
// or you could just output matches to a List first
matches.ToList().ForEach(i => Console.WriteLine(i));

When it comes to joins I strongly prefer the linq query syntax, though you could equally use Lambda expression they usually look a bit messy...

theburningmonk