1

I'm trying to learn lambda operations and I can't figure out how to get this to work. What I have gets the opposite of what I need, but I can't figure out what I need to do to reverse it.

DataTable table1;
List<string> list1;
var duplicates = list1.AsEnumerable()
    .Where(r => table1.AsEnumerable()
    .Any(r2 => r2["ID"] as string == r.ToString()));

I basically have a shopping cart which in this example is table1. When the user goes to add an item to their cart, I want to make sure said items don't already exist in their cart. So my list1 has the ID's of the items they are about to put in their cart and the datatable is their current cart contents, and has a column called ID. So I would like to have the result be the remaining items of list1 that were not found in the ID column of my table.

The above will get all the items that are in the shopping cart.

I thought just changing the == to != would work, but it does not. I found a bunch of different threads that had similar problems, but all the ones I found were comparing two objects that were the same, like two datatables with the same columns or two List<string> objects. They were saying to use the keyword Except. Every time I tried to duplicate these results, I had an issue with the syntax.

Here was one thing I tried from another thread, but it gives me a syntax error for the select statement. I tried to base this off of the answer in the following thread: Use LINQ to get items in one List<>, that are not in another List<>

var result = list1.Where(p => !table1.Select(p2 => p2["RegID"] == p.ToString()));

I would appreciate any help you can give me!

--Joseph

edit Here is my working code.

DataTable table1;
List<string> list1;
var duplicates = list1.AsEnumerable()
    .Where(r => table1.AsEnumerable()
    .All(r2 => r2["ID"] as string != r.ToString()));
Community
  • 1
  • 1
jpaugh78
  • 99
  • 2
  • 10

3 Answers3

4

You almost get it, just need to negate (!) the Any expression:

list1.Where(s => !table1.AsEnumerable().Any(r => r.Field<string>("ID") == s));

Alternatively, you can use All:

list1.Where(s => table1.AsEnumerable().All(r => r.Field<string>("ID") != s));
Arturo Menchaca
  • 15,783
  • 1
  • 29
  • 53
  • Both of these are returning the entire list for some reason. Not sure what is wrong. But I was able to alter my code to use all and != to get it to work. I updated my answer. Thanks for the help though! – jpaugh78 Jun 01 '16 at 18:26
  • @jpaugh78: well you need to get the result of the query, like `var duplicates = list1.Where(...)`, maybe that was the problem. – Arturo Menchaca Jun 01 '16 at 18:30
  • That makes sense. I was using your whole answer without setting it to a variable because I wasn't sure exactly how to implement it. You did help me further understand some of the syntax though. Thanks! – jpaugh78 Jun 01 '16 at 18:32
3

Don't just invert the ==, also invert the Any. In this case that would be All.

Put together that would read as

Where all entries in the database are not this item

or short

If this item isn't in the database.

Manfred Radlwimmer
  • 13,257
  • 13
  • 53
  • 62
0

Personally I think that code is hard to read, I prefer methods like Except or Intersect for readability.

To get started:

// added
numbers1 = new List<int> { 1, 2 };
numbers2 = new List<int> { 3, 4 };
numbers2.Except(numbers1).Dump(); // shows 3, 4

// removed
numbers1 = new List<int> { 1, 2, 3, 4, 5 };
numbers2 = new List<int> { 1, 2, 3, 4 };
numbers1.Except(numbers2).Dump(); // shows 5

// overlapping
numbers1 = new List<int> { 1, 2, 3 };
numbers2 = new List<int> { 2, 3, 4 };
numbers1.Intersect(numbers2).Dump(); // shows 2, 3

In your case

var duplicates = list1.Intersect(table1.AsEnumerable()
                     .Select(s => s["ID"].ToString()))
                     .Any();

will do.

Peter Bons
  • 26,826
  • 4
  • 50
  • 74
  • 2
    `Excpet` and `Intersect` are also Linq methods. – juharr Jun 01 '16 at 18:19
  • 1
    @juharr are they? It are extension methods living in the System.Collection.Generics namespace.. https://msdn.microsoft.com/en-us/library/bb908822(v=vs.90).aspx – Peter Bons Jun 01 '16 at 18:21
  • 1
    `creates really ugly code to read` ... that exectues pretty well on the dbms instead of the webserver. But hey, who wants short performant code anyways, right? – Manfred Radlwimmer Jun 01 '16 at 18:21
  • @PeterBons Did you notice the "(Defined by Enumerable.)"? They are extension methods defined in `System.Linq.Enumerable`. The MSDN documentation will show all extension methods that apply to a given type. – juharr Jun 01 '16 at 18:22
  • @ManfredRadlwimmer Except that there is no DB in play here. – juharr Jun 01 '16 at 18:25
  • @PeterBons Linq is not just the namespace, but the entire Query Language itself ([see this article](https://msdn.microsoft.com/en-us/library/mt693052.aspx)) First praragraph: "You can use LINQ to query any enumerable collections such as List" – Manfred Radlwimmer Jun 01 '16 at 18:26
  • Thanks for trying to help Peter. I'm not sure how to use this since I need to compare a list with a datatable, but maybe I can use this sometime when i'm comparing lists! – jpaugh78 Jun 01 '16 at 18:30
  • @jpaugh78 that would be solved using var duplicates = list1.Intersect(table1.AsEnumerable().Select(s => s["ID"].ToString())); – Peter Bons Jun 01 '16 at 18:51