Henry
Henry

Reputation: 32905

Sort an array of string by length in ColdFusion?

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

Answers (5)

Kotwarrior
Kotwarrior

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

Russ
Russ

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

Mike Causer
Mike Causer

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

Sergey Galashyn
Sergey Galashyn

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

jboursiquot
jboursiquot

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

Related Questions