0

I have class like below

public class Item { public long Id {get;set;} public long GroupingId {get;set;} public long Weight {get;set;} public long Tolerance {get;set;} } 

Now I have list of Items with different grouping id. Lets say

List<Item> items = GetItems(); 

Now I need to group based groupings id, and make check for each item in that group against each other. How would I do that in LINQ efficiently. Any help much appreciated.

IDictionary<long, long[]> matches = new Dictionary<long, long[]>(); foreach(groupedItems in items.GroupBy(p=>p.GroupingId)) { foreach(item in groupItems) { // Check item with other items in group items // and if condition is correct take those 2 items. // lets say the condition is // (item.Weighting - other.Weighting) > item.Tolerance // duplicates could be removed // lets condition for 1,2 is done means no need to do 2 against 1 var currentItem = item; var matchedOnes = groupItems.Where(p => (Math.Abs(p.Weighting - currentItem.Weighting) > currentItem .Tolerance) && p.Id != currentItem.Id) .ToList(); if (!matchedOnes.Any()) continue; matches.Add(currentItem.Id, matchedOnes .Select(p=>p.Id).ToArray()); } } 

I did like above, but its giving duplicates(1,2 and 2,1 are duplicates).. How would I remove the duplicate checks

5
  • 1
    What exactly checks do you want to do? It seems that you want to throw all items with difference more than tolerance, but in this case you should compare value with average value, but you compare with other values in group. In this case, if you have any pair of items with difference more than tolerance you will throw away whole group. Commented May 28, 2013 at 11:20
  • I need to check the difference in weighting of two items in the group with greater than the item 1 tolerance. Math.Abs(item1.weighting-item2.weighting) > item1.Tolerance Commented May 28, 2013 at 11:24
  • first make distinct list of GroupingId Like List<long> lst = items.Select(h => h.GroupingId).Distinct().ToList(); Commented May 28, 2013 at 11:32
  • 2
    Please, define answer field. Commented May 28, 2013 at 12:20
  • @FrancescoDeLisi I have updated it. There is no field called answer Commented May 28, 2013 at 14:10

3 Answers 3

3

As a simple change, try exchanging p.Id != answer.Id for p.Id > answer.Id in your groupItems.Where(...) line.

Sign up to request clarification or add additional context in comments.

1 Comment

Excellent, if answer means what you think and belongs to groupItems.
0

Do you mean this:

 var items = new List<Tuple<int, int>>() { new Tuple<int, int>(1, 1) , new Tuple<int, int>(1, 2) , new Tuple<int, int>(2, 2) , new Tuple<int, int>(2, 2) , new Tuple<int, int>(2, 3) , new Tuple<int, int>(3, 2) , new Tuple<int, int>(3, 3) , new Tuple<int, int>(4, 4) , new Tuple<int, int>(4, 3) , new Tuple<int, int>(4, 4) }.Select(kp => new { id = kp.Item1, data = kp.Item2 }); var res = ( from i1 in items from i2 in items where i1.id < i2.id /* Custom Filter goes there */ && i1.data == i2.data select new { i1 = i1, i2 = i2 } ); 

1 Comment

Check out Tuple.Create which can save you a couple of characters since you need not specify the generic types: msdn.microsoft.com/en-us/library/dd387181.aspx
-2

Try this

var pairs = Enumerable.Range(0, items.Count()).SelectMany(index => items.Skip(index + 1).Select(right => new { left = items.elementAt(index), right })); var matches = pairs.Where(item => (item.left.Weight - item.right.Weight) > item.left.Tolerance); 

The first part creates all the pairs that have to be compared like (1, 2), (1, 3), (2, 3) for a collection of 3 items. The second part selects the pairs that match your condition.

I've also removed the grouping code which you already figured out (items = groupItems).

1 Comment

Is it me, or is this a scenario where LINQ causes completely unreadable code?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.