1

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?

1

5 Answers 5

3

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.

Sign up to request clarification or add additional context in comments.

4 Comments

This doesn't work for CF9 which is what the question is about. However it is correct in that the other answer is buggy.
This should be the comment on the other answer.
Sorry, i don't have enough reputation to comment on other people's stuff.
FYI, you do now :-)
3

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"]

1 Comment

You know, it could be even more memory-effective than quick sort since there's no nested loops... Should check, but need to start my work day :)
2

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;
    }
  }

Comments

1

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)

6 Comments

The equivalent using arraySort would be: arraySort(ary, function (left, right) { return len(left) > len(right); }); Also, it modifies the original array, whereas _.sortBy() does not.
I haven't noticed any performance drawbacks to closures in Railo 4 or CF 10, but I haven't done any thorough speed tests.
Again: downvoting cos it's answering the question for the wrong version of CF. Plus you'd not use a bespoke solution even in CF10 when the functionality is built-in.
The question does not specify a version of CF. At the time of my response, CF 10 was the latest version.
Yes, but I am commenting today @russ, just like everyone else who is looking at the question & answer from now on. And in it's current context, the answer is "wrong".
|
0

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" ]

1 Comment

The above answer has an error. Closure does not expect a boolean value.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.