Sorting Numerical List

I have 576 objects all named, "Person " plus a number from 1-576. Then I made a list of every object and tried to sort it with System.Linq. Instead of sorting it by “Person 1” “Person 2”… “Person 10” etc, it sorts it by “Person 1” “Person 10” “Person 100”… “Person 2” It’s treating person 100 as person 1 instead of 100 and it’s treating person 2 as coming after any person with 1 as the first digit.

List<GameObject> temp = new List<GameObject>();
        temp.AddRange(GameObject.FindGameObjectsWithTag("Person").OrderBy(go => go.name));

It’s actually not a numerical list, it’s a list of strings. That being said, maybe these will help…
https://stackoverflow.com/questions/1022203/sorting-strings-containing-numbers-in-a-user-friendly-way

there is no easy way to do this, as you have to write a custom sorting comparer which can be quite cumbersome.
but there is a hack that you could apply.

if your names always have a space between the word and the number, you can split the two and pad the number so that all numbers are of the same length, but have leading zeroes.

var gos = GameObject.FindGameObjectsWithTag("Person");
const int DIGITS = 4; // how many total digits you'd like
string[] paddedNames = new string[gos.Length];

for(int i = 0; i < gos.Length; i++) {
  var name = gos[i].name;
  name.SplitOnce(name.IndexOf(" "), out var word, out var num);
  paddedNames[i] = $"{word} {num.PadLeft(DIGITS, '0')}";
}

Array.Sort(paddedNames);
// paddedNames are now properly sorted (but have zeroes)
// this is a general purpose extension (should go into a separate static class)
static public void SplitOnce(this string s, int index, out string left, out string right) {
  if(index < 0 || index >= s.Length - 1) { left = s; right = string.Empty; }
    else { left = s.Substring(0, index); right = s.Substring(index + 1); }
}

you can also do something like this (probably even better, because no zero padding)

var gos = GameObject.FindGameObjectsWithTag("Person");
var sortedList = new SortedList<int, int>();

for(int i = 0; i < gos.Length; i++) {
  var name = gos[i].name;
  name.SplitOnce(name.IndexOf(" "), out _, out var num);
  sortedList.Add(int.Parse(num), i);
  // here we use sorted list that is auto-sorted,
  // but we store the original index as well
}

var finalList = new List<GameObject>();
foreach(var item in sortedList) {
  // because this foreach is in sorted order
  // we can use the stored index to fetch the original GO
  finalList.Add(gos[item.Value]);
}

// you can do finalList.ToArray() if you need an array

(edit: this has to be modified to work with the words as well, it’s just an idea;
final solution is down, so keep reading)

if this still isn’t good enough for you try to look for alphanumeric (or natural) sorting comparer.
it is easy to run, you just do

GameObject.FindGameObjectsWithTag("Person").OrderBy(go => go.name, new SomeComparer());

or you can use Array.Sort on the result without having to use Linq

var result = GameObject.FindGameObjectsWithTag("Person");
Array.Sort(result, new SomeComparer());

but you have to code the entire class that does this
you may want to check out this (the answer by J.D. with 28 likes)
or this (the answer by VVS with 4 likes)

finally, and personally I think this one is a winner
you can make a very small comparison method, and use List.Sort instead

var gos = GameObject.FindGameObjectsWithTag("Person");
var list = new List<GameObject>(gos);
list.Sort((a, b) => NaturalComparer(a.name, b.name));
// DONE

static int NaturalComparer(string a, string b) {
  a.SplitOnce(a.IndexOf(" "), out _, out var num1);
  b.SplitOnce(b.IndexOf(" "), out _, out var num2);
  int n1 = int.Parse(num1), n2 = int.Parse(num2);
  if(n1 < n2) return -1;
  if(n1 > n2) return +1;
  return 0;
}

the last comparer only takes into account the numbers, which isn’t sufficient for your case
so let’s make it smarter

static int NaturalComparer(string a, string b) {
  // check if there are spaces (returns -1 if none were found)
  int i1 = a.IndexOf(" "), i2 = b.IndexOf(" ");

  // split the strings (works with -1 just fine)
  a.SplitOnce(i1, out var text1, out var num1);
  b.SplitOnce(i2, out var text2, out var num2);

  // compare the textual parts
  int c = text1.CompareTo(text2);

  // if there were spaces and textual parts were equal
  // compare numbers only
  if(i1 >= 0 && i2 >= 0 && c == 0) {
    // if you had a space between two words, this will blow up
    // so be careful (in that case, it has to be smarter than this)
    int n1 = int.Parse(num1), n2 = int.Parse(num2);
    if(n1 < n2) return -1; else if(n1 > n2) return +1;
    return 0;
  }

  // otherwise sort machine-like alphabetically
  return c;
}

this is probably the nimblest natural sorter you’ll ever come across on the internet.
yes I’m the humblestest of persons, I know. (pshh it’s quite limited, but I said it’s hacky)

If you don’t want to rely on spaces or any such delimiter, you can try using Regex

i.e.

var num = Regex.Match(a, @"\d+$"); // will find digits in your string