How do I use List.Sort()?

I’m trying to order points in a list from least to greatest using List.Sort(). However, I keep getting an error “ArgumentException: At least one object must implement IComparable.” I know I need to use the IComparable library and create a CompareTo method, but after looking around for a long while, I couldn’t really find a good in-depth guide for how to do this. All the documentation I found was pretty hard to understand, so I didn’t really get anywhere.

Can anyone explain what I need to do?

 Vector2 playerVector = player.transform.position;
Vector2 startVector = randomPos;
Vector2 calculatedVector_1 = new Vector2(x, y_equation1);
Vector2 calculatedVector_2 = new Vector2(-x, y_equation2);


Vector2[] points = {playerVector, startVector,  calculatedVector_1, calculatedVector_2};
List<Vector2> pointsOrdered = new List<Vector2>();

pointsOrdered = points.ToList();

pointsOrdered.Sort();

line.GetComponent<LineRenderer>().SetPosition(0, pointsOrdered[0]);
line.GetComponent<LineRenderer>().SetPosition(1, pointsOrdered[1]);
line.GetComponent<LineRenderer>().SetPosition(2, pointsOrdered[2]);
line.GetComponent<LineRenderer>().SetPosition(3, pointsOrdered[3]);

You’ll have to use the Sort method that takes a delegate, or sort with LINQ. Check Stackoverflow for guidance.

I’m more concerned with this copy-pasta code snippet. Any getter method or property that returns a reference that you need more than once gets assigned to a variable and re-used. This is faster, easier to read, easier to debug.

var lineRenderer = line.GetComponent<LineRenderer>();
lineRenderer.SetPosition(0, pointsOrdered[0]);
lineRenderer.SetPosition(1, pointsOrdered[1]);
lineRenderer.SetPosition(2, pointsOrdered[2]);
lineRenderer.SetPosition(3, pointsOrdered[3]);

Also, a loop would help:

var lineRenderer = line.GetComponent<LineRenderer>();
for (int i = 0; i < 4; i++)
    lineRenderer.SetPosition(i, pointsOrdered[i]);

I’ve been looking at StackOverflow as well, but I’ve had no luck—it’s pretty confusing to me. Capsule you possibly give an example using delegates?

Also, yes, I was meaning to put that code snippet into a for loop, but I got caught up in the IComparable stuff and forgot about it.

List.Sort has various overloads:

(msdn - unity relies on C# which is a language developed and designed independent of unity, msdn is a wonderful resource for learning about the C# language and the .net framework)

You can use a ‘Comparison’ which is a delegate with the shape:

public delegate int Comparison<in T>(T x, T y);

Note it takes in 2 values and outputs an int.

If the output is 0, you’re saying they’re equal in terms of comparing (if you sorted by first letter only for instance this would return 0 if x and y were strings starting with the same letter).

< 0 means that x is < y, meaning it should come before in an ascending sort

0 means that x is > y, meaning it should come after in an ascending sort

see the documentation for a long for example:
List<T>.Sort Method (System.Collections.Generic) | Microsoft Learn))

Note there are other Sort overloads that take in other options that the delegate. This includes sorting via an ‘IComparer’, which is similar to the delegate, but instead is an interface with a Compare method of the same shape as above. This allows you to use a more object oriented approach to defining your sort method.

There is also a version that lets you sort only a specific range in the list. And a version with no parameters which uses the default comparer for T:

I tried adding

                Comparer<Vector2> defComp = Comparer<Vector2>.Default;

                pointsOrdered = points.ToList();

                pointsOrdered.Sort(defComp);

But it didn’t work.

I decided to use OrderByDecending because I’m not smart enough to understand IComparables.

                Vector2 playerVector = player.transform.position;
                Vector2 startVector = randomPos;
                Vector2 calculatedVector_1 = new Vector2(x, y_equation1);
                Vector2 calculatedVector_2 = new Vector2(-x, y_equation2);


                Vector2[] points = {playerVector, startVector,  calculatedVector_1, calculatedVector_2};
                List<Vector2> pointsOrdered = new List<Vector2>();
                pointsOrdered = points.ToList();

                pointsOrdered = pointsOrdered.OrderByDescending(p => p.x).ToList();
                pointsOrdered = pointsOrdered.OrderByDescending(p => p.y).ToList();


                line.GetComponent<LineRenderer>().SetPosition(0, pointsOrdered[0]);
                line.GetComponent<LineRenderer>().SetPosition(1, pointsOrdered[1]);
                line.GetComponent<LineRenderer>().SetPosition(2, pointsOrdered[2]);
                line.GetComponent<LineRenderer>().SetPosition(3, pointsOrdered[3]);

I doubt the default comparer for Vector2 compares the way you want.

You follow this post with another post where you order by the x property and then the y property. Thing is… I don’t know if this is what you wanted either. You’re effectively just sorting by y… sure for like values of y there’ll be some sort of pattern of the order of x’s, but that’s incidental to IF the y’s are equal AND the sort algorithm used, as well as is relying on float equality which is hazy at best. If you want both to be considering you may want to use ‘ThenBy’, but even then, do you?

You’re also creating a lot of lists… just sticking to your OrderByDescending you could go with something more like:

var renderer = line.GetComponent<LineRenderer>();
int i = 0;
foreach (var p in (new Vector2[] {playerVector, startVector, calculatedVector_1, calculatedVector_2}).OrderByDescending(p => p.x).ThenByDescending(p => p.y))
{
    renderer.SetPosition(i, p);
    i++;
}

There is a way to write this a IComparer or Comparison, but it’s far more complicated than the linq solution. So it’s best you stick with this.

I still wonder though… what is up with the sorting by x THEN by y? I can’t be certain if my code is doing exactly what you want as I don’t know what you’re actually expecting.

Are you trying to sort by distance per chance?

What does the order by descending.x and y mean? Does it just mean that it orders based on the x values or y values? I think I may just need to use x.
I’m just trying to extend the line renderer to be a bit longer than the end points.

That’s what I’m asking you… what do you expect this sort to accomplish?

Note that these positions appear to be in global space. So if you say:
“I think I may just need to use x”, what you’re saying is you’re sorting your points along the x-axis in a descending direction… basically you’re making it point in the -x direction.

Which also brings in another stipulation. When setting the positions of a line renderer the points passed in need to in the coordinate space configured on the LineRenderer:

Since you’re passing in what appear to be world space coordinates, you should probably make sure this is set true.

But yeah, back to what you want.

You want the line renderer to be a bit longer?

So is this what your calculatedVector_1 and calculatedVector_2 are? You used some equation to make them further from something?

If that’s so… I suspect you’re probably trying to sort by distance from that something. So your orderby should be in ascending order of distance from that position. Something like:

var somepos = *the position youre measuring from*;
var points = new Vector2[] {playerVector, startVector, calculatedVector_1, calculatedVector_2};
var ordered = points.OrderBy(p => Vector2.Distance(p, somepos)).Cast<Vector3>().ToArray();
line.GetComponent<LineRenderer>().SetPositions(ordered);

(note - I just slapped that together real quick here in the browser… honestly I may have typoed something)

But again, we gotta work on defining what it is you’re exactly trying to accomplish.

Mind you that this is what programming is. Explaining to a computer in intricate technical terms what exactly you want. If you can’t describe what you want to us or yourself, you’re going to have a real hard time explaining it to a computer in a specialized language you’re only just learning.

I’m looking over my code, and I was just trying to order my points based on the x value. I think I figured it all out! Thank you!