76

I have two lists:

  List<int> data1 = new List<int> {1,2,3,4,5};
  List<string> data2 = new List<string>{"6","3"};

I want do to something like

var newData = data1.intersect(data2, lambda expression);

The lambda expression should return true if data1[index].ToString() == data2[index]

Gareth
  • 5,140
  • 5
  • 42
  • 73
Merni
  • 2,842
  • 5
  • 36
  • 42
  • 1
    possible duplicate of [Check two List's for the same numbers](http://stackoverflow.com/questions/480033/check-two-listints-for-the-same-numbers) – Joshua Drake Feb 22 '14 at 22:28
  • 1
    @JoshuaDrake I don't think it's a duplicate; that question does not consider using a lambda for custom determination of equality. – ApproachingDarknessFish Feb 23 '14 at 03:58
  • @ValekHalfHeart I probably should have just noted it as related, I somehow missed the difference in data types in this question. – Joshua Drake Feb 24 '14 at 18:36

4 Answers4

105

You need to first transform data1, in your case by calling ToString() on each element.

Use this if you want to return strings.

List<int> data1 = new List<int> {1,2,3,4,5};
List<string> data2 = new List<string>{"6","3"};

var newData = data1.Select(i => i.ToString()).Intersect(data2);

Use this if you want to return integers.

List<int> data1 = new List<int> {1,2,3,4,5};
List<string> data2 = new List<string>{"6","3"};

var newData = data1.Intersect(data2.Select(s => int.Parse(s));

Note that this will throw an exception if not all strings are numbers. So you could do the following first to check:

int temp;
if(data2.All(s => int.TryParse(s, out temp)))
{
    // All data2 strings are int's
}
Community
  • 1
  • 1
George Duckett
  • 31,770
  • 9
  • 95
  • 162
14

If you have objects, not structs (or strings), then you'll have to intersect their keys first, and then select objects by those keys:

var ids = list1.Select(x => x.Id).Intersect(list2.Select(x => x.Id));
var result = list1.Where(x => ids.Contains(x.Id));
alexkovelsky
  • 3,880
  • 1
  • 27
  • 21
8

From performance point of view if two lists contain number of elements that differ significantly, you can try such approach (using conditional operator ?:):

1.First you need to declare a converter:

Converter<string, int> del = delegate(string s) { return Int32.Parse(s); };

2.Then you use a conditional operator:

var r = data1.Count > data2.Count ?
 data2.ConvertAll<int>(del).Intersect(data1) :
 data1.Select(v => v.ToString()).Intersect(data2).ToList<string>().ConvertAll<int>(del);

You convert elements of shorter list to match the type of longer list. Imagine an execution speed if your first set contains 1000 elements and second only 10 (or opposite as it doesn't matter) ;-)

As you want to have a result as List, in a last line you convert the result (only result) back to int.

Slava Kovalchuk
  • 523
  • 4
  • 7
-4
public static List<T> ListCompare<T>(List<T> List1 , List<T> List2 , string key )
{
    return List1.Select(t => t.GetType().GetProperty(key).GetValue(t))
                .Intersect(List2.Select(t => t.GetType().GetProperty(key).GetValue(t))).ToList();
}
billybob
  • 2,859
  • 6
  • 35
  • 55
  • 5
    Please provide appropriate explanation along with code. Even comments in code shall work. Also, please understand that code styling improves readability of your answer. If you happen to limit your code to 80 chars per line, the answer will not need the scrolling. Also, your answer has a long chain of function calls that could be explained in code for better understanding. – Vasif Nov 15 '16 at 23:31
  • Why even use reflection? We know the list-types. In particular we know the type for *every* element, which is either integer or string. Queyring the value of every element within the list via reflection is pure overkill and overcomplicates this question a lot. – MakePeaceGreatAgain Aug 03 '17 at 07:09