Reputation: 1690
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
Upvotes: 0
Views: 1848
Reputation: 38179
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).
Upvotes: -2
Reputation: 50114
As a simple change, try exchanging p.Id != answer.Id
for p.Id > answer.Id
in your groupItems.Where(...)
line.
Upvotes: 3
Reputation: 6692
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 }
);
Upvotes: 0