I have 2 lists, namely clist with 4 Vector3 values C1, C2, C3, C4 and second list named plist with 4 vector3 values P1, P2, P3, P4. I need to find the minimum distances from the vectors in clist to the vectors in plist. For example, need to find the distance from C1 to P1, P2, P3 and P4. C2 to P1, P2, P3 and P4. C3 to P1, P2, P3, P4. C4 to P1, P2, P3, P4.
For that I have added a struct to store this data like this:
public struct CPDistance
{
public GameObject p;
public GameObject c;
public float distance;
}
and created a new list of this struct using the code:
public List<CPDistance> tempstruct = new List<CPDistance>();
and I had found the distance between these vectors using the code:
foreach (var ca in clist)
{
foreach (var pa in plist)
{
CPDistance cpd = new CPDistance();
cpd.p = pa;
cpd.c= ca;
cpd.distance = Vector3.Distance(ca.transform.position, pa.transform.position);
tempstruct.Add(cpd);
}
}
IEnumerable<CPDistance> query = tempstruct.OrderBy(x => x.distance);
foreach (var item in query)
{
Debug.Log(item.c.name " " item.p.name " " item.distance);
}
On running the above code I get an output like this:
C4 P1 0.5526165
C2 P3 1.242753
C1 P4 1.519395
C3 P1 1.891354
C2 P4 2.189372
C1 P3 2.390067
C4 P2 4.378077
C3 P2 5.170161
C3 P3 7.519557
C1 P2 7.856441
C3 P4 7.938454
C2 P1 8.108953
C1 P1 8.33768
C2 P2 8.851195
C4 P3 9.264006
C4 P4 9.530743
In the image it can be seen that, C1 is near to P4, C2 is near to P3, C4 is near to P1, and the remaining C3 is near to P2. I need to get the output like this:
C1 P4 1.519395
C2 P3 1.242753
C4 P1 0.5526165
C3 P2 5.170161
I have heard that there is a code named Firstordefault where condition can be given to the variable query to get the above desired output. I have given the code like this:
foreach (var i in clist)
{
query.FirstOrDefault(x => x.p == i);
}
But its not giving the desired output. Can someone help me to find what's the issue with the usage of FirstorDefault code.
CodePudding user response:
If you were merely trying to find the closest point to each item, you could easily do that with LINQ:
var closestToEachP = data.GroupBy(e => e.p)
.Select(g => g.OrderBy(e => e.distance).First())
.ToList();
But it looks like you need each point to be removed as an option whenever we find another item close to it. To do that, you'll need to keep track of which items you've found. That would look something like this:
var seenPValues = new HashSet<string>();
var seenCValues = new HashSet<string>();
var closestPairs = new List<CPDistance>();
foreach (var element in data.OrderBy(e => e.distance))
{
if(!seenPValues.Contains(element.p) && !seenCValues.Contains(element.c))
{
seenPValues.Add(element.p);
seenCValues.Add(element.c);
closestPairs.Add(element);
}
}