jrfdelgado
jrfdelgado

Reputation: 33

How to remove duplicate elements in a list using LINQ based on a custom condition?

I'm trying to eliminate all the elements in a list that obey a certain condition. Specifically, I have a list of Points and I need to filter this list such that duplicate points should be removed from the list (Note that for the purpose of this project a point that is within a certain threshold of another is considered to be the same, and hence is a duplicate). I've been trying to use LINQ to do this but I keep having Points that should have been eliminated (according to my conditions). My code is as follows:

var fingers = from p1Index in Enumerable.Range(0, fingAux.Count())
              from p2 in fingAux.Skip(p1Index + 1)
              let p1 = fingAux.ElementAt(p1Index)
              where (p1.X > p2.X + tresh) || (p1.X < p2.X - tresh)
              select p1;

What am I doing wrong?

Upvotes: 0

Views: 193

Answers (3)

bubbinator
bubbinator

Reputation: 495

Simply replace this line:

where (p1.X > p2.X + tresh) || (p1.X < p2.X - tresh)

with this line

where (p1.X < p2.X + tresh) && (p1.X > p2.X - tresh))

Basically, if some code is doing the exact opposite of what you want, try inverting the operators.

Upvotes: 0

D Stanley
D Stanley

Reputation: 152566

The problem with your code is that you're selecting points that are more than tresh away from at least one point.

The problem with your method is "equality" must be commutative, meaning if pA == pB and pB == pC, then pA == pC. If your condition is "points within tresh of each other are equal" then you have an issue, since I could have three points A, B, and C, that are within tresh of each other, but A and C are not.

e.g. if tresh is 5, and I have points A=3, B=7, and C=9, then A and B are "equal", B and C are "equal", but A and C are not.

Another option would be to "round" each point to the nearest tresh and group them, selecting the first from each group:

fingAux.GroupBy(p => Math.Round(p1.X / tresh))  // assuming X and/or tresh are floating-point
       .Select(g => g.First());   // take the first point of each group

Upvotes: 2

Sidharth Panwar
Sidharth Panwar

Reputation: 4654

Try this:

var filtered = from p in fingAux
           where !(fingAux.Any(f1 => p.X < (f1.X + tresh)) select p

Upvotes: 0

Related Questions