How to Order Floats According to Its Values?

Hello,

Here is what i want to do exactly:

Imagine 5 cubes in screen and each of these cubes has a name. The X position of these cubes are equal floats and which means there are 5 floats in the script. I show the names of the cubes with a UI text in the screen like; “FirstCube SecondCube ThirdCube FourthCube FiveCube”, as all together(it’s like a sentence like this). When i change the place of a cube, i want its name to change its place according to cube’s place in the screen. For example; if i change ThirdCube’s place with FirstCube’s place, i want text to update it self as “ThirdCube SecondCube FirstCube FourthCube FiveCube”. I have done this manually as;

if(Manager.firstCubeX<Manager.secondCubeX&&Manager.firstCubeX<Manager.thirdCubeX&&Manager.firstCubeX<Manager.fourthCubeX......)
{
//Do something.
}

But this way seem too long for me. How can i make this with a short way? Reordering cubes will update the text according to places of the cubes.

Edit: It must be without using box colliders and triggers. Only the values of floats.

Thanks!

Put the cubes in an array. Sort the array by the cube’s x-positions.

C# has a built-in Array.Sort method. If the elements in the array are naturally comparable (eg. if it’s an array of floats), you can just do:

Array.Sort(myArray);

And it’s sorted! Your cube transforms are not naturally comparable*, though, so you have to help. Here’s an example:

public Transform[] cubeArray;

void Update() {
    //You can pass methods as arguments to certain functions, like Array.Sort.
    //Array.Sort uses the function to compare elements to know what order to put them in.
    Array.Sort(cubeArray, CompareByX);
}

private int CompareByX(Transform t1, Transform t2) {
    if (t1.position.x < t2.position.x)
        return -1;
    else if (t1.position.x > t2.position.x)
        return 1;
    else
        return 0;

    //If you're interested in seeing what happens behind the scenes, uncomment this Debug.Log:
    //Debug.Log(t1.name, t2.name);
}

If cubeArray is a GameObject[ ], just rewrite CompareByX to take two GameObject, and compare their transform.position.

  • Naturally comparable is a bit of a misnomer, as that’s a relative concept. Array.Sort can manage to sort your array on it’s own if the type of the things in the array implements the IComparable interface. All the built-in numbers does, as well as things like Date-classes and strings (which automatically compares alphabetically). You can make your own methods be IComparable, in which case you can auto-sort them. Things like Vector3 (transform.position) have not been made IComparable because there’s no obvious, default way to compare them.
2 Likes

Here’s a compact-syntax example using Linq. This will reorder the cubes list by X position left to right. Then it will get all the cubes names in a list, and join them together with spaces into a string. Then it will print that string out.

using UnityEngine;
using System.Collections.Generic;
using System.Linq;

public class Example : MonoBehaviour {
    public List<GameObject> cubes;

    private void Awake() {
        cubes = cubes.OrderBy(cube => cube.transform.position.x).ToList();
        List<string> cubeNames = cubes.ConvertAll(cube => cube.name);
        string cubeNameString = string.Join(" ", cubeNames.ToArray());
        Debug.Log(cubeNameString);
    }
}

Edit: Ah ninja’d by Baste!

This way I’m sure has more overhead than Baste’s method.

I figured that if somebody’s asking how to sort 5 elements, showing them a lambda might be a bit premature (no offense! We all started out knowing nothing)

It was the first thing that came to mind for how I would do it, but I agree it’s a bit of a leap for a beginner.

Thank you so much for your answers. I really appreciated. I will try them and i will talk about the results. Thanks a lot again.

Hello again. Thank you so much for the solution. It works great but i have one another question. I want to sort by using float values, not according to transform.position.x. Position X of the game object equals a float and which means there are five floats. I want to sort from high value to low. How can i change this script to float?
I have tried to convert it but i couldn’t be successful at it. It must be something like this:

cubesFloat = cubesFloat.OrderBy(..................).ToList();
List<string>cubeFloatNames= cubesFloat.ConvertAll(..................);
stringcubeNameString=string.Join("",cubeFloatNames.ToArray());

I have solved what i want to do. Thank you much again for your helps.

1 Like

Just so you know, to sort low to high you can use the Sort method. To go high to low, you can use Sort, followed by a Reverse method.

OrderBy takes a parameter for which value to sort by. Since you have a list of floats, you can sort by the float itself.

Sort() method is good enough for that, but you can use OrderBy and OrderByDescending for that as well, you’ll get the same result but with a bit of extra typing:

List<float> floatList = new List<float>();

floatList.OrderBy(f => f);
// or
floatList.OrderByDescending(f => f);
// or
floatList.Sort();
// or
floatList.Sort();
floatList.Reverse();
2 Likes

Great! Thanks a lot!

Hello again jeffreyschoch,

I have one more question about ordering cubes. I am using your method and it works great but i have noticed a bug with this codes today. When i add a cube to the list and remove it from the list and when i do this loop for a few time(quickly) by changing their places(to left, to middle or to right), the system confuses and it doesn’t order the names of the cubes correctly. For example, it put the name of the cube which is in the most left to the most right and it put the name of the cube which is in the most right to the most left. I mean the strings stay in the wrong positions that can be mean that the system may not update the cubes positions, it may use the old position.(By the way, i run your method under Update function) Can you please take a look at it?

Thanks a lot!

Sure, would you mind posting your code as you have it right now?

void Update()
{
targets=targets.OrderBy(cube=>cube.transform.position.x).ToList();
List<string>cubeNames=targets.ConvertAll(cube=>cube.name);
string cubeNameString=string.Join("",cubeNames.ToArray());
stringsOnScreen=cubeNameString;
}

and i run a code according to their places like:

void Update()
{
if(firstCube<secondCube&&secondCube<thirdCube&&thirdCube<fourthCube)
{
//Do something according if the targets take position like that.
}
}

Even if i do that, sometimes the strings on the screen seems weird. While the order of cubes are as firstCube and secondCube and thirthCube and fourthCube, the string must be “firstCube secondCube thirthCube fourthCube”. But sometimes it seems as “fourthCube secondCube thirthCube firstCube” or something like that. Even if i order the cube from first to four. Why could it be?

Shouldn’t you be comparing firstCube.position.x < secondCube.position.x, etc? What kind of variable is “firstCube” and “secondCube”? Where are those coming from?

A bit more context would be helpful. I can’t really say what the problem is from those snippets. The first snippet will update the string “stringsOnScreen” every frame to be accurate to the left-to-right order of the cubes, but I don’t know how you’re using “stringsOnScreen” or what “firstCube” & “secondCube” and so on are.

Sory i forgot to put their transform.position.x values at the end. They should be like that:

if(firstCube.transform.position.x<secondCube.transform.position.x&&secondCube.transform.position.x<thirdCube.transform.position.x&&thirdCube.transform.position.x<fourthCube.transform.position.x)
{
//Do something according if the targets take position like that.
}

stringsOnScreen is equals to a Canvas text. It is like that: theSentence.text = stringsOnScreen;

By the way, i think i found the solution. It is not about with this part:

void Update()
{
targets=targets.OrderBy(cube=>cube.transform.position.x).ToList();
List<string>cubeNames=targets.ConvertAll(cube=>cube.name);
string cubeNameString=string.Join("",cubeNames.ToArray());
stringsOnScreen=cubeNameString;
}

Thank you so much again for helping.

1 Like