0

I'm trying to fetch a list of items that have the following characteristics. I need to highlight the ones that only differ by the field "item_differ". I have therefore written the following code to find the desired records. This code does work for what I'm looking for but was wondering if there are smarter ways(both fewer lines and better performing or any)

void Main()
{
    var MyItemList = GetItemList();

    var Pair_of_items = (from p in MyItemList
                         let true_items = from f in MyItemList
                                          where (new { p.item1, p.item2, p.item3, 
                                                       p.item4, p.item5}
                                          == new { f.item1, f.item2, f.item3, 
                                                   f.item4, f.item5}) 
                                          && f.item6_differ != p.item6_differ                                                 
                                              select f                                                
                                              select true_items).SelectMany(x => x);
}

// Define other methods and classes here

public class MyClass
{
    public string item1 { get; set; }
    public string item2 { get; set; }
    public string item3 { get; set; }

    public string item4 { get; set; }
    public string item5 { get; set; }
    public bool item6_differ { get; set; }
}

Any comment will be highly appreciated.

200_success
  • 7,286
  • 1
  • 43
  • 74
Bertrand Paul
  • 97
  • 2
  • 9
  • 1
    Btw.: the `where`-clause seems quite complicated to me, why not simply use `where p.Item1 == f.Item1 && ...`? Creating an anonymous type for the sake of comparing its properties to another instance of another type (which shares the same properties making it semnatically identical) is a bit weird. – MakePeaceGreatAgain Nov 29 '16 at 11:11
  • The other question is will it perform poorer compared to simply testing each property one against the other? – Bertrand Paul Nov 29 '16 at 11:14
  • What do you think your check for equality of the anonymous features will do? It also compares every property of the type. – MakePeaceGreatAgain Nov 29 '16 at 11:15
  • Agree, i guess i need to get my hands on ILSpy. – Bertrand Paul Nov 29 '16 at 11:18

2 Answers2

2

I think this returns the same result but much more efficient:

var Pair_off_items = 
    from p in MyItemList
    join f in MyItemList 
    on new {p.item1, p.item2, p.item3, p.item4, p.item5} equals new {f.item1, f.item2, f.item3, f.item4, f.item5}
    where f.item6_differ != p.item6_differ
    select f;
Community
  • 1
  • 1
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • 1
    Wow, this acceptance came really fast... – MakePeaceGreatAgain Nov 29 '16 at 11:23
  • @HimBromBeere: true, to be honest, i wasn't sure if it returns the same result but OP's query seems to be overcomplicated for no reason and the join is always [more efficient](http://stackoverflow.com/questions/5551264/why-is-linq-join-so-much-faster-than-linking-with-where), especially in Linq-To-Objects. – Tim Schmelter Nov 29 '16 at 11:25
  • Well, that is because i had the same idea in mind, not sure it was more efficient. – Bertrand Paul Nov 29 '16 at 11:25
  • Anyway you may consider to check for every property yourself instead of relying on anonymous-type-checking. I feel the `on new {...}` counter-intuitive, but that might be my personal opinion. – MakePeaceGreatAgain Nov 29 '16 at 11:29
  • @HimBromBeere: I totally agree. Thanks – Bertrand Paul Nov 29 '16 at 11:31
  • +1. (Had a group by in mind myself) `var Pair_off_items = from p in MyItemList group p by new {p.item1, p.item2, p.item3, p.item4, p.item5} into g where g.GroupBy(f=>f.item6_differ).Count() > 1 from p in g select p;` – Me.Name Nov 29 '16 at 11:32
  • @HimBromBeere: but that is how join works on multiple properties in any database driven linq provider and it's also working in Linq-To-Objects. – Tim Schmelter Nov 29 '16 at 11:32
  • @Me.Name And what hinders you on writing this as answer? – MakePeaceGreatAgain Nov 29 '16 at 11:32
  • @HimBromBeere Partly because there already was an accepted answer, but mainly because I was away on an appointment :D – Me.Name Nov 29 '16 at 12:19
  • @Me.name: I think you solution is worth posting. I would actually try it out and see if it performs better. Thanks – Bertrand Paul Nov 29 '16 at 13:09
1

An alternative is to use a group by to first group on items 1 through 5. (which has the maintainability advantage of defining those properties once in the criteria) and then check the groups for item6_differ

var Pair_off_items = from p in MyItemList
    group p by new {p.item1, p.item2, p.item3, p.item4, p.item5} into g
    where g.GroupBy(f=>f.item6_differ).Count() > 1
    from p in g
    select p;

In the query above g will contain all items with the same items 1 through 5. There are multiple ways to check if a group contains different item6 values. Above a second groupby is used, but you could play around with other options. e.g. where g.Select(f=>f.item6_differ).Distinct().Count() > 1 should also work, as should let first = g.First().item6_differ where g.Any(f=>f.item6_differ != first)

Me.Name
  • 12,259
  • 3
  • 31
  • 48