- Home /
Add Elements in Array in Inspector with alphabetical sorting
Hey guys,
I have a lot of elements to add to an array, and I wonder if there is a faster way than drag and drop each element in the inspector. I wan`t them in alphabetical order. I tried to select them all al drag them right in the array of the inspector, but it sorts them by a wierd manner. Is there a simple way of doing that, but sorting in alphabetical order ?
Thanks a lot !
Claude
What kind of "element"? Unity doesn't provide such a function out of the box since it depends on the element type. The easiest is to write a small editor helper class to sort the array, but without the exact type it's a bit tricky...
@Siflou, you are right, I also reported this a while ago. Dragging game objects to the inspector one by one is annoying, and if you have more than a handful, and you drag them to the top of the array in the inspector, you get a random order. This is terribly annoying. I did not find any workaround, other than dragging them one by one...
For larger arrays, I simply avoid using the inspector, and find a less time consu$$anonymous$$g way of doing things.
@CHPedersen , you are right but you are also missing the point.
Take 20 game objects that are named "$$anonymous$$onster1" to "$$anonymous$$onster20", now drag them onto a public GameObject[] monsters
.
You will see that Unity places them with no order whatsoever, this is just some random default, with no logic at all (maybe based on meta data or who knows). This by itself, makes no sense and is NEVER usable.
On the other hand, if such an action will place them ordered by their name, it will be usable. Plain and simple.
I agree that people should not rely on the order to make coding decisions, but just for sanity, it would make a lot of sense for you to see them ordered properly in the inspector.
As a last point I should mention, that if indeed Unity will implement it this way, you will lose nothing, only gain something.
Lets start by assu$$anonymous$$g that the user does not want random...
If the user does not want random, he should follow Jamora's suggestions below, and implement an editor script that sorts the elements on demand. :)
Answer by Jamora · Sep 27, 2013 at 11:17 AM
As CHPedersen argues, having thise done automatically by Unity is a bad idea. Luckily Unity allows us to implement our own behavior to some extent.
You need to create either a custom inspector for your class, or create a property drawer if you have this behavior in multiple scripts. I would then make a button which, when pressed, sorts the list. Sorting the list every repaint or addition/removal seems terribly wasteful to me.
The next thing you need to do is implement a sorting algorithm. I would recommend the Radix sort (hint: use a dictionary in C#) for sorting strings. You can sort anything you can provide an enumeration for.
EDIT:
Because I assume you've already implemented the sorting functionality, I'll show you how I did it, for reference:
MyBaseClass _target;
void OnEnable ()
{
_target = (MyBaseClass)target;
}
private void SortArray(){
string ordering = "abcdefghijklmnopqrstuvxyz ";
Dictionary<char, List<string>> buckets = new Dictionary<char, List<string>>();
string[] targetArray = _target.stringArray;
List<string> tempList = new List<string>();
int maxLength = -1;
foreach(string s in targetArray){
if(s.Length > maxLength)
maxLength = s.Length;
}
//divide into buckets
for(int character = maxLength-1; character>-1;character--){
for(int i=0;i<targetArray.Length;i++){
char currentChar;
//an if-else -construct here would be more efficient, but I find this to be more illustrative
try{
currentChar = targetArray[i][character];
}catch (System.IndexOutOfRangeException e){
currentChar = ' ';
}
if(!buckets.ContainsKey(currentChar))
buckets.Add(currentChar,new List<string>());
buckets[currentChar].Add(targetArray[i]);
}
//combine buckets
for(int i=0;i<ordering.Length;i++){
if(buckets.ContainsKey(ordering[i])){
foreach(string s in buckets[ordering[i]])
tempList.Add(s);
}
}
targetArray = tempList.ToArray();
tempList.Clear();
buckets.Clear();
}
_target.stringArray = targetArray;
}
Answer by JoeStrout · Apr 20, 2015 at 04:51 PM
FWIW, in case somebody else stumbles across this question as I did, here's the solution I have settled on for now. In the script containing an array property, add a bit of code to create a contextual menu, like this:
[ContextMenu ("Sort Frames by Name")]
void DoSortFrames() {
System.Array.Sort(frames, (a,b) => a.name.CompareTo(b.name));
Debug.Log(gameObject.name + ".frames have been sorted alphabetically.");
}
In this example, I have a "public Sprite[] frames" property; just change all occurrences of "frames" to whatever your own array property is, and it ought to work. (Also, this is C#; changes would be needed for JavaScript.)
I like this solution because it goes right in the script with the array property, rather than needing a separate editor script. Also I much prefer letting the designer sort when they want to, rather than (say) sorting at runtime, which forces a requirement that your assets be named a certain way.
I'd rather something generic that could fix the problem across the board, but barring that, this is the next best thing.
Answer by hudi · Aug 01, 2014 at 11:40 AM
The same thing annoyed me very much and I found a simple solution.
1) Make a public list
public List<YourType> Objects;
2) Make a class implementing IComparer
class Comparer : IComparer<YourType>
{
int IComparer<YourType>.Compare(YourType a, YourType b)
{
if (a.ToString().Length < b.ToString().Length) return -1;
else if (a.ToString().Length > b.ToString().Length) return 1;
else return System.String.Compare(a.ToString(), b.ToString());
}
}
3) In the Start or Awake function:
Comparer comparer = new Comparer();
Objects.Sort(comparer);
4) Voila!
Your objects are sorted alphabetically. :)
That's not what the OP was asking for, and not generally useful, either. If I've got a script (which I do) that takes an array of, say, textures (which it does), I don't want to REQUIRE that every user of this script name their textures in alphabetical order. But often artists do exactly that (Boom0001.png, Boom0002.png, etc.). They're already sorted correctly in the Hierarchy and Scene views, in fact. We just want to be able to drag these over into an array and have that order preserved -- or, failing that (which Unity does), have the OPTION of cleaning up Unity's mess by sorting them. Once. $$anonymous$$anually. At edit time.
It's close though, and it helped me. Saying it is not generally useful is really arrogant so kudos to you. The biggest downside is sorting at runtime and even that is not a problem for small arrays. Even your solution doesn't do what you're pointing finger at. It just doesn't sort things at runtime which is I must say really great. So, good job.
Sorry, I think you're interpreting "generally useful" in a different sense from what I intended. I mean "not useful in the general case" -- the technical meaning of "general," not the casual meaning. It still may be quite useful in a variety of specific cases, of course.
Answer by WoozyBytes · Apr 16, 2015 at 04:56 PM
It would be easier to use a Generic List Instead of built in arrays and you can just call _myList.Sort();
and it's sorted .
Here's an example
using UnityEngine ;
using System.Collections.Generic;
public class MyScript : MonoBehaviour
{
public List<string> _myList = new List<string>() ;
// Use this for initialization
void Start ()
{
SortList();
}
void SortList ()
{
_myList.Sort();
}
}
Regards
Yes, this is certainly more sensible than the diversion above about implementing your own sorting algorithm. But it still doesn't answer the basic question of: how do you add this functionality to the editor, and in a general way? I've been searching for this for a couple of days now, and am amazed to find no good solution yet.
I implemented the sorting algorithm in few lines. Why is this so better really? Generic Sort() didn't do for me so I wrote my own sorting. Geez.
Hi !!!
@JoeStrout - in the editor i'm Not sure, maybe with C# you can create an editor script that covers it , however i don't know how to do it lol.
@hudi - Everytime i use List.Sort();
it works , for numbers and strings at least.
Usually if I need something to be sorted i just make a function for it, and use it as necessary.
Well i didn't realize that it was meant to work in the editor.
@JoeStrout The accepted answer points to a custom inspector
Won't that work ?
Regards.
Yes, a custom inspector will work, but it requires a separate script placed in a different (editor) folder in your project hierarchy. I prefer the solution where we just add a contextual menu item, because that can be all self-contained in the same script.