Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Sorting a Generic List in JaveScript

Discussion in 'Scripting' started by MitchStan, Mar 17, 2012.

  1. MitchStan

    MitchStan

    Joined:
    Feb 26, 2007
    Posts:
    568
    I have a generic List of GameObjects (boxes) that are instantiated all about the playing level. The boxes are kept in a List -- boxList as you can see from the code below.

    How do I, in Unity JavaScript, do a sort of the List based on the distance of each box to the gameobject stagingArea?

    I've been trying to implement the List.Sort() method with List.CompareTo() but everything I can find is in C#.

    Can anyone help me with the proper syntax in JS to sort by distance?

    Thanks for any help.

    MItch

    Code (csharp):
    1. import System.Collections.Generic;
    2.  
    3. var boxPrefab : GameObject;
    4. var ground : GameObject;
    5. var stagingArea : GameObject;
    6.  
    7. var boxList : List.<GameObject>;
    8.  
    9. function Start ()
    10. {
    11.     for (n = 0; n < Random.Range(2,4); n ++)
    12.     {
    13.         box = Instantiate(boxPrefab);
    14.         box.transform.position.x = Random.Range(-ground.renderer.bounds.extents.x, ground.renderer.bounds.extents.x);
    15.         box.transform.position.z = Random.Range(-ground.renderer.bounds.extents.z, ground.renderer.bounds.extents.z);
    16.         box.transform.position.y = ground.transform.position.y + ground.renderer.bounds.extents.y + box.renderer.bounds.extents.y;
    17.        
    18.         boxList.Add(box);
    19.     }
    20. }
     
  2. Atin Skrita

    Atin Skrita

    Joined:
    Feb 18, 2011
    Posts:
    94
    Just import System.Linq and use OrderBy(function(x){return x.name;}) to order the game objects by name. Like this:
    Code (csharp):
    1.  
    2. //set boxList to the value of boxList whose elements are ordered by name
    3. boxList = boxList.OrderBy(function(x){return x.name;}).ToList();
    4.  
    System.Linq provides functions to every class that implements IEnumerable these functions help with managing elements inside an enumerable class. OrderBy orders the elements from first to last based on basic values like,
    int, boolean, string, float, double, ect. If you want the values ordered from last to first just add .Reverse() right after the OrderBy(function(x)) call.
     
  3. MitchStan

    MitchStan

    Joined:
    Feb 26, 2007
    Posts:
    568
    Thanks for the advice. I'll try it if I can figure out the proper syntax. Do you know if this will work in Unity Javascript?
     
  4. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Not sure if it'll work on mobile either.
     
  5. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    Atin's syntax looks fine to me, already in Unityscript.

    You can also use the List's Sort method to sort it in-place, if you pass it a suitable function. e.g. something like this:

    Code (csharp):
    1.  
    2. function compareDistanceToSelf(a : Vector3, b : Vector3)
    3. {
    4.     var a_dist = Vector3.Distance(transform.position, a);
    5.     var b_dist = Vector3.Distance(transform.position, b);
    6.     return a_dist.CompareTo(b_dist);
    7. }
    8.  
    9.     ...
    10.     boxList.Sort(compareDistanceToSelf);
    11.     ...
    12.  
     
  6. MitchStan

    MitchStan

    Joined:
    Feb 26, 2007
    Posts:
    568
    Thanks, George. I believe that is close to what I'm looking for but your code snippet confuses me. compareDistanceToSelf takes a pair of Vector 3 arguments in the function definition, but then in line 9 of your code you don't pass any parameters to the function. Is that right?

    I'll try and figure it out but unfortunately I'm kinda over my head. Anything you can add to clarify would be greatly appreciated.

    Mitch
     
  7. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    Yes, we're not calling the comparison function, we're passing it to Sort as a delegate, so that Sort can call it lots of times with different pairs of vectors. Each time, it tells Sort whether 'a' should come before or after 'b'.
     
  8. MitchStan

    MitchStan

    Joined:
    Feb 26, 2007
    Posts:
    568
    Thanks for the further explanation, George. I'm getting an error message:

    Code (csharp):
    1. import System.Collections.Generic;
    2.  
    3. var boxPrefab : GameObject;
    4. var ground : GameObject;
    5.  
    6. var numberOfBoxes : int = 25;
    7.  
    8. var boxList : List.<GameObject>;
    9.  
    10. function Start ()
    11. {
    12.     for (n = 0; n < Random.Range(numberOfBoxes/2, numberOfBoxes); n ++)
    13.     {
    14.         box = Instantiate(boxPrefab);
    15.         box.transform.position.x = Random.Range(-ground.renderer.bounds.extents.x, ground.renderer.bounds.extents.x);
    16.         box.transform.position.z = Random.Range(-ground.renderer.bounds.extents.z, ground.renderer.bounds.extents.z);
    17.         box.transform.position.y = ground.transform.position.y + ground.renderer.bounds.extents.y + box.renderer.bounds.extents.y;
    18.        
    19.         box.transform.parent = ground.transform;
    20.        
    21.         boxList.Add(box);
    22.     }
    23.     boxList.Sort(compareDistanceToSelf);
    24. }
    25.  
    26. function compareDistanceToSelf(a : Vector3, b : Vector3)
    27. {
    28.     var a_dist = Vector3.Distance(transform.position, a);
    29.     var b_dist = Vector3.Distance(transform.position, b);
    30.     return a_dist.CompareTo(b_dist);
    31. }
    32.  
    33.  
    Getting the following error message:

    Any thoughts? This is Unity Javascript. DO delegates work in JS?

    Mitch
     
  9. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    Sorry, I didn't look closely at your code before. Your boxList is a list of GameObjects, not Vector3s. You need to write a compare function that takes two GameObjects instead.

    Delegates work, but I don't think you can define new ones.
     
  10. MitchStan

    MitchStan

    Joined:
    Feb 26, 2007
    Posts:
    568
    Thank you, George. I modified the code for GameObjects and it works great. Thank you for pointing that out. I appreciate your guidance on this. Many thanks.
     
  11. tirb

    tirb

    Joined:
    Sep 24, 2012
    Posts:
    1
    Thank you so much - works perfectly! Tried to solve this problem for days and didnt find any solution!
     
  12. minicub

    minicub

    Joined:
    Nov 26, 2012
    Posts:
    3
    How exactly did you modify it? It did it like this:

    Code (csharp):
    1. function CompareDistanceToPlayer(a : GameObject, b : GameObject)
    2. {
    3.     var a_dist = Vector3.Distance(transform.position, a.position);
    4.     var b_dist = Vector3.Distance(transform.position, b.position);
    5.     return a_dist.CompareTo(b_dist);
    6. }
    but i get the error:

     
  13. MitchStan

    MitchStan

    Joined:
    Feb 26, 2007
    Posts:
    568
    Try this:


    Code (csharp):
    1. function CompareDistanceToPlayer(a : GameObject, b : GameObject)
    2. {
    3.     var a_dist = Vector3.Distance(transform.position, a.transform.position);
    4.     var b_dist = Vector3.Distance(transform.position, b.transform.position);
    5.     return a_dist.CompareTo(b_dist);
    6. }
     
  14. minicub

    minicub

    Joined:
    Nov 26, 2012
    Posts:
    3
    Unfortunately not,i get the same error. Here's my full script if you'd care to take a look

    Code (csharp):
    1. import System.Collections.Generic;
    2.  
    3. var targets : List.<Transform>;
    4. var selectedTarget : Transform;
    5.  
    6. function Start () {
    7.     targets = new List.<Transform>();
    8.     selectedTarget = null;
    9.     AddAllEnemies();
    10. }
    11.  
    12. function AddAllEnemies()
    13. {
    14.     var go : GameObject[] = GameObject.FindGameObjectsWithTag("Enemy");
    15.     for(var enemy : GameObject in go)
    16.     {
    17.         AddTarget(enemy.transform);
    18.     }
    19. }
    20.  
    21. function AddTarget(enemy : Transform)
    22. {
    23.     targets.Add(enemy);
    24. }
    25.  
    26. function CompareDistanceToPlayer(a : GameObject, b : GameObject)
    27. {
    28.     var a_dist = Vector3.Distance(transform.position, a.transform.position);
    29.     var b_dist = Vector3.Distance(transform.position, b.transform.position);
    30.     return a_dist.CompareTo(b_dist);
    31. }
    32.  
    33. function SortByDistance()
    34. {
    35.     targets.Sort(CompareDistanceToPlayer);
    36. }
    37.  
    38. function TargetEnemy()
    39. {
    40.     selectedTarget = targets[0];
    41. }
    42.  
    43. function Update () {
    44.     if(Input.GetKeyDown(KeyCode.Tab))
    45.     {
    46.         TargetEnemy();
    47.     }
    48. }
     
  15. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    You have a List of Transform, but the sort function is using GameObjects. You can't mix types.

    --Eric
     
  16. minicub

    minicub

    Joined:
    Nov 26, 2012
    Posts:
    3
    Thanks a lot Eric! That was it.
     
  17. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    Sorry to wake this thread up, but how efficient is a generic list's sort function on mobile? I need to be able to sort my cars in a racing game by three factors: current lap, current way-point, and current way-point distance. ATM, I am using System.Array.Sort, but I am finding this to be extremely expensive on the mobile device! Apparently, generic lists are faster...

    Is this true? o_O
     
  18. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Generic Lists are slower than built-in arrays. They use built-in arrays behind the scenes, but have a little overhead on top of that.

    --Eric
     
  19. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    In that case, what's the fastest array-like class? o_O
     
  20. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Built-in arrays.

    --Eric
     
  21. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    In that case then, I will see how built-in arrays help.
    I think beforehand, it used java script arrays, but I am not sure. Right now, it's using a generic list!