Search Unity

[SOLVED] Sort array objects by distance ?

Discussion in 'Scripting' started by skyLark9, Jan 17, 2020.

  1. skyLark9

    skyLark9

    Joined:
    May 2, 2018
    Posts:
    135
    Hi. I have two arrays. one float calculate the distance for trees. Other for the tree objects. The float array I can sort it but the trees array I don't know how to sort it. I want to sort trees array as i did on distance array to get the Y value later for the first and second one.

    1. public GameObject[] trees;
    2. public float[] distances;
    3. public float[] PosY;

    4. void Start()
    5. {
    6. trees = GameObject.FindGameObjectsWithTag("tree");
    7. distances = new float[2];
    8. PosY= new float[2];

    9. }

    10. void Update()
    11. {

    12. distances[0] = Vector3.Distance(transform.position, trees[0].transform.position);
    13. distances[1] = Vector3.Distance(transform.position, trees[1].transform.position);
    14. System.Array.Sort(distances);

    15. // sort trees
    16. // get Y value
      PosY[0] = trees[0].transform.position.y;
    17. PosY[1] = trees[1].transform.position.y;
    18. print("First Tree " + PosY[0] + "// Second Tree one" + PosY[1]);
    1. }
     
  2. Chris-Trueman

    Chris-Trueman

    Joined:
    Oct 10, 2014
    Posts:
    1,261
    You could roll your own sort method. When swapping indices on the distance array, do the same swap on the trees array.

    Or

    You can use only one array for the trees and then sort using a custom comparer that compares distance. Some info on how to do that https://www.csharp-examples.net/sort-array/
     
    skyLark9 likes this.
  3. skyLark9

    skyLark9

    Joined:
    May 2, 2018
    Posts:
    135
    I'm not that good with array. I know how to sort distance because i'm using "Vector3.Distance" values. But trees is object. compares distance ! I'm a bet of lost here. Show me how to do it.
     
  4. Vectorbox

    Vectorbox

    Joined:
    Jan 27, 2014
    Posts:
    232
    You can use 'System.Linq' to sort your objects by distance. In the following example script, the object transforms are sorted when you click the 'left mouse' button...

    Code (csharp):
    1. using UnityEngine;
    2. using System.Linq;
    3.  
    4. public class Test : MonoBehaviour {
    5.    // Public References
    6.    public Transform[] trees;
    7.  
    8.    // --
    9.    void Update () {
    10.        //
    11.        if (Input.GetMouseButtonDown(0)) {
    12.            trees = trees.OrderBy((d) => (d.position - transform.position).sqrMagnitude).ToArray();
    13.        }
    14.    }
    15. }
     
  5. mbaske

    mbaske

    Joined:
    Dec 31, 2017
    Posts:
    473
    You can wrap objects with an IComparable and use Array.Sort

    Code (CSharp):
    1. public struct SortableByDistance : IComparable<SortableByDistance>
    2. {
    3.     public GameObject obj;
    4.     public float distance;
    5.  
    6.     public SortableByDistance(GameObject obj, float distance)
    7.     {
    8.         this.obj = obj;
    9.         this.distance = distance;
    10.     }
    11.  
    12.     public int CompareTo(SortableByDistance other)
    13.     {
    14.         return distance.CompareTo(other.distance);
    15.     }
    16. }
     
    skyLark9 likes this.
  6. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,325
    You can create a custom IComparer for your trees and use it with Array.Sort.

    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Compare : MonoBehaviour
    6. {
    7.     public Transform[] trees;
    8.     private DistanceComparer distanceComparer;
    9.  
    10.     private void Awake()
    11.     {
    12.         distanceComparer = new DistanceComparer(transform);
    13.     }
    14.  
    15.     private void Update()
    16.     {
    17.         Array.Sort(trees, distanceComparer);
    18.     }
    19.  
    20.     public class DistanceComparer : IComparer<Transform>
    21.     {
    22.         private Transform target;
    23.  
    24.         public DistanceComparer(Transform distanceToTarget)
    25.         {
    26.             target = distanceToTarget;
    27.         }
    28.  
    29.         public int Compare(Transform a, Transform b)
    30.         {
    31.             var targetPosition = target.position;
    32.             return Vector3.Distance(a.position, targetPosition).CompareTo(Vector3.Distance(b.position, targetPosition));
    33.         }
    34.     }
    35. }
     
    fabianschmidt2512 and skyLark9 like this.
  7. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,325
    Curipoc, Vectorbox and skyLark9 like this.
  8. skyLark9

    skyLark9

    Joined:
    May 2, 2018
    Posts:
    135
    Thank you so much guys for all this information.
     
  9. Riderfan

    Riderfan

    Joined:
    Jan 10, 2013
    Posts:
    514
    Never use LINQ. And especially never use LINQ in an update loop. LINQ generates a HUGE, no, MASSIVE - amount of garbage for the system to collect and clean up. LINQ is arguably the #1 way to kill your frame rate.
     
    Madsen87 and DragonSix like this.
  10. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    necro to complain about a tool that lots of people use regularly

    I use linq, it's perfectly fine. Yes you shouldn't overdo linq, especially in Update. But it's perfectly fine to intermitently use it as it is well... very powerful.

    Lots of stuff you do in code is expensive... it's why computers are better today than they were 20 years ago. We want to do MORE expensive/costly things. Don't be afraid to do them just because you're scared it "might" cost you something. Of course it will... the fastest code is no code at all.

    OP should get it done, keep on moving, and if the game ever ends up being too slow. Well they run the profiler and if it turns out this linq statement is the bottleneck... THEN you rewrite it to be more efficient.

    This of course isn't to say always use linq. If you happen to know off the top of your head a simple way to get it done another way. That's cool too. Point is... get the job done as well as you can. You can always refactor later if it proves to be slow.

    Especially if that optimization is minor... linq is not the horrible beast people make it out to be. Linq doesn't create massive amounts of garbage, it creates some garbage... if it's creating massive amounts that's usually because you're throwing large amounts of data at it (large collections) and probably doing things that require copies of it being made... in which case your hand written version will likely also create copies as well (unless you really know your ish well, in which case, you likely already understanding the risks of linq and how to optimize like a pro). You know, like how someone points out the Array.Sort that takes 2 arrays... ok, that one is going to mean I have to create an array as large as my current one which will then become garbage!
     
    Last edited: May 25, 2020
    DaveBars, Squid117 and Vectorbox like this.
  11. Chris-Trueman

    Chris-Trueman

    Joined:
    Oct 10, 2014
    Posts:
    1,261
    To say NEVER use something, is bad advice. Especially a valuable tool like LINQ, because it CAN cause issues. So can rendering too much. Should we avoid rendering? Or do we try to tame the beast so it can become our friend.

    When my friend wanted to learn Unity and programming, he came across various posts that read "avoid properties, they can kill performance." So when he saw me nilly willy making properties in my classes, we had to have a chat about the difference between MonoBehaviour properties and the ones you create. Now when I see "never" or "avoid" for something that is useful. I can't help but think of that moment of trying to explain to someone, what they read was wrong. Having to walk them through why its not a bad thing, when you don't do what someone else did with it.
     
  12. Riderfan

    Riderfan

    Joined:
    Jan 10, 2013
    Posts:
    514
    Never use LINQ.
     
    MostHated and DragonSix like this.
  13. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    mmm hmmm
     
    Bunny83 likes this.
  14. DJ_Design

    DJ_Design

    Joined:
    Mar 14, 2013
    Posts:
    124
    In that case, never use rider.
     
  15. MostHated

    MostHated

    Joined:
    Nov 29, 2015
    Posts:
    1,235
    Rider can automatically take your Linq statement and convert it to standard code, which technically makes this a worse comment than "Never use LINQ". Udonegoofed.
     
    Lurking-Ninja likes this.
  16. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    Necroed a thread to respond to a comment you clearly missed the point of.

    They were making the point that "Riderfan" (someone whose name implies they like Rider) is merely espousing arbitrary opinion by responding with arbitrary opinion. It doesn't matter what Rider can/can't do... it's conjecture for conjecture's sake.
     
    Bunny83 likes this.
  17. MostHated

    MostHated

    Joined:
    Nov 29, 2015
    Posts:
    1,235
    I am well aware of what he was doing. You must have missed that I was also doing the same. Plus, my necro wasn't nearly as bad as his was.
     
    Last edited: Apr 30, 2021
  18. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    Yeah, there's was bad as well.

    I don't see how you're making the same "opinion is opinion" riff though. You seem to be saying "your example is bad because Rider has this feature"... where's the unsubstantiated opinion there? Where is the conjecture?

    conjecture - an opinion or conclusion formed on the basis of incomplete information.

    By definition not including that Rider can convert linq to non-linq code is "incomplete information" only adding to the evidence their statement was conjecture... I still don't see how yours is.

    But, maybe that's just me. I'm outs...
     
    Last edited: Apr 30, 2021
  19. MostHated

    MostHated

    Joined:
    Nov 29, 2015
    Posts:
    1,235
    If you interpreted what I have said as anything other than replying to a dumb joke with another dumb joke, that's on you. There was absolutely no want or need for a reply to it in the first place.
     
  20. DJ_Design

    DJ_Design

    Joined:
    Mar 14, 2013
    Posts:
    124
    I was not making any relevant correlation to Rider's ability to process LINQ .
    Sorry if that went straight over your head at light speed.
    I was saying the point is null and void, it makes no sense saying "Never use LINQ".
    That's just dumb. So I responded with an equally dumb statement, "In that case never use Rider,
    because it makes about as much sense as what he said.

    Now, I won't say "you done goofed" because that's just another dumb thing to say. :)
     
    Last edited: May 3, 2021
  21. MostHated

    MostHated

    Joined:
    Nov 29, 2015
    Posts:
    1,235
    Jesus christ, I know exactly what you were saying. The only thing that seems to have gone over someone's head is that I was taking an equally pointless jab at both comments with a joke that at least Rider serves a purpose, unlike your comment.