-1

I'm finding lots of post on how to compare two List using except but I can't find anything explaining how to compare properties of two list.

I have two Models

FruitBasket
{
  ......
   public int[] Fruit {get; set;}
}

Fruit
{
   public int Id {get; set;}
   ......
}

The FruitBasket.Fruit property has an array of numbers which corresponds to the Fruit.Id. However there are orphans in the FruitBaskets that I need to weed out.

For example FruitBasket.Fruit would contain 1,2,3,4,5 but there would only be a Fruit 1, a Fruit 2, a Fruit 3. So I need to find 4 and 5 in the FruitBasket and correct the FruitBasket.

I have written an ugly dual ForEach looping through FruitBaskets and Fruit trying to find the deltas and I'm getting outrageous results because I'm just not smart enough to figure it out.

List<int> missing = new List<int>();

foreach (var basket in lstBaskets)
{
   foreach (var frt in lstFruits)
   {
      if (!basket.Fruit.Contains(frt.Id))
      {
        missing.Add(frt.Id);
      }
   }
 }

Further there as got to be a more elegant way to accomplish this? Surely this is a common business need and there is a performant way of doing it?


Note

Note that one is a List property (FruitBaskets.Fruit) is being compared to Fruit which is just a List.

GPGVM
  • 5,515
  • 10
  • 56
  • 97
  • 3
    Is `lstBaskets` a `List`? Is `lstFruits` a `List`? You can use a SelectMany to flatten the collection. Use this: `missing = lstBaskets.SelectMany(s => s.Fruit).Select(s => s.Id).Except(lstFruits.select(s => s.Id)).ToList()` – user2023861 Jul 08 '16 at 14:48
  • So you just want to find list differences? – Jacobr365 Jul 08 '16 at 14:48
  • I need to update the OP to clarify and the title. I'm actually comparing a List property to a List. – GPGVM Jul 08 '16 at 14:50
  • @GPGVM, I made it an answer. SelectMany can be a little confusing. – user2023861 Jul 08 '16 at 14:52
  • Unclear what you're trying to do. Do you want to identify unknown ID values in `basket.Fruit`? The code you show doesn't do that. It identifies the fruits that are not in the basket. So if you have fruits {1, 2, 3}, and the basket contains {1, 3, 5}, the loop code you've shown will add `2` to the `missing` list. – Jim Mischel Jul 08 '16 at 15:00
  • `missing` can contain duplicates? Do you want to fill all your fruit-baskets with missing? Then the missing-list will not help at all because it doesn't tell you which basket missed what fruit(s). – Tim Schmelter Jul 08 '16 at 15:01
  • I have made an answer too, and was downvoted without a reason. Love so much SO. What do you want to do, can you give an example of Input... Expected output... Actual output... ? – meJustAndrew Jul 08 '16 at 15:04
  • From your description, it seems like what you want is the intersection: `basket.Fruit = basket.Fruit.Intersect(Fruit.Select(f => f.Id)).ToList();`. See [Enumerable.Intersect](https://msdn.microsoft.com/en-us/library/bb460136(v=vs.100).aspx) – Jim Mischel Jul 08 '16 at 15:12

1 Answers1

2

Since you have a collection of collections, you can use SelectMany to flatten the nested collections:

List<int> missing = lstBaskets
    .SelectMany(s => s.Fruit)
    .Select(s => s)
    .Except(lstFruits.Select(s => s.Id))
    .ToList();
user2023861
  • 8,030
  • 9
  • 57
  • 86
  • I'm having trouble with the second Select lambda Select(s => s.Id) it actually doesn't see any properties. The first SelectMany flattens it but there is no ID to then select on. Fruit in FruitBaskets is an array of int. I changed to this as we can go right to except only I get zero missing records which is wrong. List missing = lstAlbums .SelectMany(s => s.images) .Except(lstImages.Select(s => s._id)) .ToList(); – GPGVM Jul 08 '16 at 15:04
  • OH Cool s => s is a way to represent it! – GPGVM Jul 08 '16 at 15:12
  • @GPGVM, I had a small mistake. My original answer would have worked if FruitBasket contained an array of Fruit objects and not an array of integers. I removed the `.Id` and updated my answer. It works how you expect now. – user2023861 Jul 08 '16 at 15:12
  • Sorta I am getting zero results in the missing collection which isn't right. Checking my data. – GPGVM Jul 08 '16 at 15:17
  • @GPGVM, if lstBaskets contains {1,2,3} and lstFruits contains {3,4,5}, do you want missing to contain {1,2}? That's what my answer gives you based on the nested foreach loops in your question. Do you instead want missing to contain {1,2,4,5}? If so, the code will be different. – user2023861 Jul 08 '16 at 15:23
  • If FruitBasket.Fruit contained 1,2,3,4,5 but the was only Fruit.Id=1,Fruit.Id=2,Fruit.Id=3 then I would want 4 and 5 in the missing list. – GPGVM Jul 08 '16 at 15:25
  • @GPGVM, I understand that. What if instead FruitBasket.Fruit contained 1,2,3 and lstFruits contained Fruit.Id=1,Fruit.Id=2,Fruit.Id=3,Fruit.Id=4,Fruit.Id=5? In this case, `missing` will be empty even though FruitBasket.Fruit doesn't contain 4 or 5. – user2023861 Jul 08 '16 at 15:28
  • That makes sense on a individual case. But the entire collection of FruitBaskets has your scenario and mine. Your scenario there are no orphans life is good. My scenario has orphans that need to be found. – GPGVM Jul 08 '16 at 15:33