Reputation: 32905
How would you sort an array of string by length in ColdFusion?
In PHP, one can use usort
as demonstrated here: PHP: Sort an array by the length of its values?
Does ArraySort()
in CF10 support passing in a comparator function like usort
?
Upvotes: 1
Views: 1067
Reputation: 108
The above answer has an error, here is the correct way to use arraysort to sort by string length:
<cfscript>
data = [ "bb", "a", "dddd", "ccc" ];
arraySort( data, function( a, b ) {
return len(a) - len(b);
});
</cfscript>
The comparator for this function should return a number either < 0
(less than), 0
(equal) or > 0
(greater than), not a boolean. Also see the arraySort docs.
Upvotes: 3
Reputation: 1951
In Coldfusion 10 or Railo 4, you can use the Underscore.cfc library to write this in an elegant and simple way:
_ = new Underscore(); // instantiate the library
// define an array of strings
arrayOfStrings = ['ccc', 'a', 'dddd', 'bb'];
// perform sort
sortedArray = _.sortBy(arrayOfStrings, function (string) {
return len(string);
});
// sortedArray: ['a','bb','ccc','dddd']
The iterator function is called for each value in the array, and that value is passed in as the first argument. The function should return the value that you wish to sort on. In this case, we return len(string). _.sortBy always sorts in ascending order.
(Disclaimer: I wrote Underscore.cfc)
Upvotes: 1
Reputation: 8314
In CF10 you can indeed use a closure with ArraySort().
eg1. sort by length alone.
<cfscript>
data = [ "bb", "a", "dddd", "ccc" ];
arraySort( data, function( a, b ) {
return len(a) < len(b);
});
</cfscript>
data == [ "a", "bb", "ccc", "dddd" ]
eg2. sort by length and alphabetically when same length.
<cfscript>
data = [ "b", "a", "dddd", "ccc" ];
arraySort( data, function( a, b ) {
return len(a) == len(b) ? compare( a, b ) : ( len(a) > len(b) );
});
</cfscript>
data == [ "a", "b", "ccc", "dddd" ]
eg3. same, only reverse the order.
<cfscript>
data = [ "b", "a", "dddd", "ccc" ];
arraySort( data, function( a, b ) {
return len(a) == len(b) ? compare( b, a ) : ( len(a) < len(b) );
});
</cfscript>
data == [ "dddd", "ccc", "b", "a" ]
Upvotes: 0
Reputation: 6956
I guess this is not going to be most flexible or even effective solution, but I was interested in the shortest version which uses built-in CFML sorting... Without comments it's just 13 lines of code :)
source = ["bb", "a", "ffff", "ccc", "dd", 22, 0];
lengths = {};
result = [];
// cache lengths of the values with index as key
for (i=1; i LTE ArrayLen(source); i++) {
lengths[i] = Len(source[i]);
}
// sort the values using 'numeric' type
sorted = StructSort(lengths, "numeric", "asc");
// populate results using sorted cache indexes
for (v in sorted) {
ArrayAppend(result, source[v]);
}
Result is ["a",0,"bb",22,"dd","ccc","ffff"]
Upvotes: 3
Reputation: 1271
You can use a quick sort algorithm along with your own custom comparator, similar to how Java's comparators work.
You can find a quickSort UDF here: http://cflib.org/udf/quickSort.
You'll need to define your own comparator to tell the function how it should do the sorting. Below is a working example. Note that you'll need in include the UDF in your page so that the quickSort function is available.
strings = ["bb", "a", "ccc"];
WriteOutput(ArrayToList(quickSort(strings, descStringLenCompare)));
//outputs a,bb,ccc
WriteOutput(ArrayToList(quickSort(strings, ascStringLenCompare)));
//outputs ccc,bb,a
//Ascending comparator
Numeric function ascStringLenCompare(required String s1, required String s2)
{
if (Len(s1) < Len(s2)){
return -1;
}else if (Len(s1) > Len(s2)) {
return 1;
}else{
return 0;
}
}
//Descending comparator
Numeric function descStringLenCompare(required String s1, required String s2)
{
if (Len(s1) < Len(s2)){
return 1;
}else if (Len(s1) > Len(s2)) {
return -1;
} else {
return 0;
}
}
Upvotes: 2