One thing you could do is automatically split out the name into two separate attributes after the user saves the name. That way, nothing changes for the user. Use regex to find the first non-number character and then put both separate parts into different attributes. Sorting by the number attribute first and then the string might still not work as empty is usually grouped together, but you could at least build custom logic to sort as needed.
In case you really want natural sorting (and this is the ordering you want):
External libraries needed:
none
Used imports:
import com.mendix.systemwideinterfaces.core.IContext;
import com.mendix.webui.CustomJavaAction;
import com.mendix.systemwideinterfaces.core.IMendixObject;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import com.mendix.core.Core;
import com.mendix.logging.ILogNode;
Java code (based on examples from https://stackoverflow.com/questions/104599/sort-on-a-string-that-may-contain-a-number; you can use whatever override you want though, below is just one example):
// BEGIN USER CODE
ILogNode logger = Core.getLogger( "NaturalSort" );
if(Input == null) {
logger.debug("Empty list");
return Input;
}
//assume at least 1 entry in list
if(!Input.get(0).hasMember(SortingAttribute)){
throw new com.mendix.systemwideinterfaces.MendixRuntimeException("Member does not exist in list: "+SortingAttribute);
}
//member exists at this point
if(Input.get(0).getValue(getContext(),SortingAttribute) instanceof String == false){
throw new com.mendix.systemwideinterfaces.MendixRuntimeException("Member " + SortingAttribute + " is not of type String.");
}
//member is of type String at this point
logger.debug("Original list:");
Input.forEach(mxobj -> {String val = mxobj.getValue(getContext(),SortingAttribute);logger.debug(val);});
Input.sort(new Comparator() {
@Override
public int compare(IMendixObject mxobja, IMendixObject mxobjb) {
String a = mxobja.getValue(getContext(),SortingAttribute);
String b = mxobjb.getValue(getContext(),SortingAttribute);
int la = a.length();
int lb = b.length();
int ka = 0;
int kb = 0;
while (true) {
if (ka == la) return kb == lb ? 0 : -1;
if (kb == lb) return 1;
if (a.charAt(ka) >= '0' && a.charAt(ka) <= '9' && b.charAt(kb) >= '0' && b.charAt(kb) <= '9') {
int na = 0;
int nb = 0;
while (ka < la && a.charAt(ka) == '0')
ka++;
while (ka + na < la && a.charAt(ka + na) >= '0' && a.charAt(ka + na) <= '9')
na++;
while (kb < lb && b.charAt(kb) == '0')
kb++;
while (kb + nb < lb && b.charAt(kb + nb) >= '0' && b.charAt(kb + nb) <= '9')
nb++;
if (na > nb)
return 1;
if (nb > na)
return -1;
if (ka == la)
return kb == lb ? 0 : -1;
if (kb == lb)
return 1;
}
if (a.charAt(ka) != b.charAt(kb))
return a.charAt(ka) - b.charAt(kb);
ka++;
kb++;
}
}
});
logger.debug("Custom natural order sort:");
Input.forEach(mxobj -> {String val = mxobj.getValue(getContext(),SortingAttribute);logger.debug(val);});
return Input;
// END USER CODE