Sort using a custom comparator: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|Perl}}: whitespace and my)
m (→‎{{header|PHP}}: whitespace)
Line 614: Line 614:
=={{header|PHP}}==
=={{header|PHP}}==
{{works with|PHP|4.4.4 CLI}}
{{works with|PHP|4.4.4 CLI}}
<lang php>
<lang php><?php
<?php
function mycmp($s1, $s2)
function mycmp($s1, $s2)
{
{
Line 625: Line 624:
$strings = array("Here", "are", "some", "sample", "strings", "to", "be", "sorted");
$strings = array("Here", "are", "some", "sample", "strings", "to", "be", "sorted");
usort($strings, "mycmp");
usort($strings, "mycmp");
?>
?></lang>
</lang>


=={{header|PL/I}}==
=={{header|PL/I}}==

Revision as of 18:10, 17 November 2009

Task
Sort using a custom comparator
You are encouraged to solve this task according to the task description, using any language you may know.

Sort an array (or list) of strings in order of descending length, and in ascending lexicographic order for strings of equal length. Use a sorting facility provided by the language/library, combined with your own callback comparison function.

Note: Lexicographic order is case-insensitive.

Ada

Works with: GNAT version GPL 2006

Comparator_Package.ads

<lang ada>package Comparator_Package is

  procedure Move_String(From : Natural; To : Natural);
  function Len (Left, Right : Natural) return Boolean;
  function Lt (Left, Right : Natural) return Boolean;
  procedure Print_Array;

end Comparator_Package;</lang>

Comparator_Package.adb

<lang ada>with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Ada.Text_Io; use Ada.Text_Io; with Ada.Characters.Handling; use Ada.Characters.Handling;

package body Comparator_Package is

  type Data is array(Natural range <>) of Unbounded_String;
 
  Strings : Data := (Null_Unbounded_String,
     To_Unbounded_String("this"),
     To_Unbounded_String("is"),
     To_Unbounded_String("a"),
     To_Unbounded_String("set"),
     To_Unbounded_String("of"),
     To_Unbounded_String("strings"),
     To_Unbounded_String("to"),
     To_Unbounded_String("sort"));
    
  procedure Move_String(From : Natural; To : Natural) is
  begin
     Strings(To) := Strings(From);
  end Move_String;
  
  function Len (Left, Right : Natural) return Boolean is
  begin
     return Length(Strings(Left)) > Length(Strings(Right));
  end Len;
 
  function Lt (Left, Right : Natural) return Boolean is
  begin
     return To_Lower(To_String(Strings(Left))) < To_Lower(To_String(Strings(Right)));
  end Lt;
  
  procedure Print_Array is
  begin
     for I in 1..Strings'Last loop
        Put_Line(To_String(Strings(I)));
     end loop;
  end Print_Array;

end Comparator_Package;</lang>

Custom_Comparator.adb

<lang ada>with Gnat.Heap_Sort_A; use Gnat.Heap_Sort_A; with Ada.Text_Io; use Ada.Text_Io; with Comparator_Package; use Comparator_Package;

procedure Custom_Comparator is begin

  Put_Line("  Unsorted Array:");
  Print_Array;
  New_Line;
  Put_Line("  Sorted in descending length:");
  Sort(8, Move_String'access, Len'access);
  Print_Array;
  New_Line;
  Put_Line("  Sorted in Ascending order:");
  Sort(8, Move_String'access, Lt'access);
  Print_Array;

end Custom_Comparator;</lang>

Output File

  Unsorted Array:
this
is
a
set
of
strings
to
sort

  Sorted in descending length:
strings
sort
this
set
to
is
of
a

  Sorted in Ascending order:
a
is
of
set
sort
strings
this
to

AutoHotkey

<lang AutoHotkey>numbers = 5,3,7,9,1,13,999,-4 strings = Here,are,some,sample,strings,to,be,sorted Sort, numbers, F IntegerSort D, Sort, strings, F StringLengthSort D, msgbox % numbers msgbox % strings

IntegerSort(a1, a2) { return a2 - a1 }

StringLengthSort(a1, a2){ return strlen(a1) - strlen(a2) }</lang>

C

Works with: POSIX version .1-2001

<lang c>#include <stdlib.h> /* for qsort */

  1. include <string.h> /* for strlen */
  2. include <strings.h> /* for strcasecmp */

int mycmp(const void *s1, const void *s2) {

   int d;
   const char *l = *(const char **)s1, *r = *(const char **)s2;
   if (d = strlen(r) - strlen(l))
       return d;
   return strcasecmp(l, r);

}

int main() {

   const char *strings[8] = {"Here", "are", "some", "sample", "strings", "to", "be", "sorted"};
   qsort(strings, 8, sizeof(const char *), mycmp);
   return 0;

}</lang>

C++

Works with: g++ version 4.1.2

<lang cpp>

  1. include <algorithm>
  2. include <string>
  3. include <cctype>

// compare character case-insensitive bool icompare_char(char c1, char c2) {

 return std::toupper(c1) < std::toupper(c2);

}

// return true if s1 comes before s2 bool compare(std::string const& s1, std::string const& s2) {

 if (s1.length() > s2.length())
   return true;
 if (s1.length() < s2.length())
   return false;
 return lexicographical_compare(s1.begin(), s1.end(),
                                s2.begin(), s2.end(),
                                icompare_char);

}

int main() {

 const std::string strings[8] = {"Here", "are", "some", "sample", "strings", "to", "be", "sorted"};
 std::sort(strings, strings+8, compare);
 return 0;

} </lang>

Clean

import StdEnv

less s1 s2
    | size s1 > size s2 = True
    | size s1 < size s2 = False
    | otherwise = lower s1 < lower s2
where
    lower :: String -> String
    lower s = {toLower c \\ c <-: s}

Start = sortBy less ["This", "is", "a", "set", "of", "strings", "to", "sort"]

Clojure

Clojure's sort function has a 2-argument version where the first argument is (like) a java.util.Comparator (in that it returns <0, 0, >0 for <,=,> comparisons respectively), and the second is the collection to be sorted. Thus the heart of this version is a comparator function that satisfies the problem spec. <lang clojure> (defn rosetta-compare [s1 s2]

 (let [len1 (count s1), len2 (count s2)]
   (if (= len1 len2)
     (compare (.toLowerCase s1) (.toLowerCase s2))
     (- len2 len1))))

</lang> Here it is in action: <lang clojure> (sort rosetta-compare items) </lang>


Common Lisp

In Common Lisp, the sort function takes a "less than" predicate that is used as the comparator. This parameter can be any two-argument function. Note: Common Lisp's sort function is destructive; for lists you should not use the original list afterwards, you should only use the return value.

For example, to sort strings case-insensitively in ascending order:

<lang lisp>CL-USER> (defvar *strings*

                '("Cat" "apple" "Adam" "zero" "Xmas" "quit" "Level" "add" "Actor" "base" "butter"))
  • STRINGS*

CL-USER> (sort *strings* #'string-lessp) ("Actor" "Adam" "add" "apple" "base" "butter" "Cat" "Level" "quit" "Xmas" "zero")</lang>

You can also provide an optional key function which maps each element to a key. The keys are then compared using the comparator. For example, to sort strings by length in descending order:

<lang lisp>CL-USER> (defvar *strings*

                '("Cat" "apple" "Adam" "zero" "Xmas" "quit" "Level" "add" "Actor" "base" "butter"))
  • STRINGS*

CL-USER> (sort *strings* #'> :key #'length) ("butter" "apple" "Level" "Actor" "Adam" "zero" "Xmas" "quit" "base"

"Cat" "add")</lang>

D

Works with: D version DMD 1.026
Library: Tango

<lang d> module customsort ; import tango.io.Stdout ; import tango.text.Ascii ; // for lexi compare

// csort need the following 2 modules import tango.util.collection.ArraySeq ; import tango.util.collection.model.Comparator ; T[] csort(T)(inout T[] arr, int function(T, T) fn_cmp) {

   ArraySeq!(T).quickSort(arr, 0, arr.length - 1, new class() 
       Comparator!(T){
           int compare(T a, T b) {
               return fn_cmp(a,b) ;
           }
       }) ;
   return arr ;

} int cmpLen(char[] a, char[] b) {

   if (a.length < b.length)
       return 1 ; // longer string come first 
   else if (a.length > b.length)
       return -1 ; 
   return 0 ; 

} int cmpLex(char[] a, char[] b) {

   return icompare(a,b) ; // case-insensitive compare

} int cmpLenThenLex(char[] a, char[] b) { // in case misunderstood the task

   return cmpLen(a,b) == 0 ? cmpLex(a,b) : cmpLen(a,b) ;

} void main() {

char[][] d = ["This", "is", "a", "set", "of", "strings", "to", "sort"]; 
Stdout(d.csort(&cmpLen)).newline ; // descending length
char[][] a = ["BbCC","4321","cBBA","Abbc","1234","bBac","baCA","BAcC"] ;
Stdout(a.csort(&cmpLex)).newline ; // ascending lexi order
char[][] m = ["Bab","abbcc","baacc","Abbc","aAcc","abBac","bba","BAC"] ;
Stdout(m.csort(&cmpLenThenLex)).newline ; // descending length then ascending lexi order

} </lang> Output:

[ strings, This, sort, set, of, is, to, a ]
[ 1234, 4321, Abbc, baCA, BAcC, bBac, BbCC, cBBA ]
[ abBac, abbcc, baacc, aAcc, Abbc, Bab, BAC, bba ]

E

/** returns a if it is nonzero, otherwise b() */
def nonzeroOr(a, b) { return if (a.isZero()) { b() } else { a } }

["Here", "are", "some", "sample", "strings", "to", "be", "sorted"] \
    .sort(fn a, b { 
              nonzeroOr(b.size().op__cmp(a.size()),
                        fn { a.compareToIgnoreCase(b) }) 
          })

Fortran

Fortran does not have builtin to sort arrays (of numbers or strings), with or without custom comparator; so we need modifying e.g. this code in order to handle strings and to accept a custom comparator.

<lang fortran>module sorts_with_custom_comparator

 implicit none

contains

 subroutine a_sort(a, cc)
   character(len=*), dimension(:), intent(inout) :: a
   interface
      integer function cc(a, b)
        character(len=*), intent(in) :: a, b
      end function cc
   end interface
   
   integer :: i, j, increment
   character(len=max(len(a), 10)) :: temp
   
   increment = size(a) / 2
   do while ( increment > 0 )
      do i = increment+1, size(a)
         j = i
         temp = a(i)
         do while ( j >= increment+1 .and. cc(a(j-increment), temp) > 0)
            a(j) = a(j-increment)
            j = j - increment
         end do
         a(j) = temp
      end do
      if ( increment == 2 ) then
         increment = 1
      else
         increment = increment * 5 / 11
      end if
   end do
 end subroutine a_sort

end module sorts_with_custom_comparator</lang>

Then we have to put our custom comparator in a module (to_lower is defined here):

<lang fortran>module comparators

 implicit none

contains

 integer function my_compare(a, b)
   character(len=*), intent(in) :: a, b
   character(len=max(len(a),len(b))) :: a1, b1
   a1 = a
   b1 = b
   call to_lower(b1)
   call to_lower(a1)
   
   if ( len(trim(a)) > len(trim(b)) ) then
      my_compare = -1
   elseif ( len(trim(a)) == len(trim(b)) ) then
      if ( a1 > b1 ) then
         my_compare = 1
      else
         my_compare = -1
      end if
   else
      my_compare = 1
   end if
 end function my_compare

end module comparators</lang>

At the end, we can test these:

<lang fortran>program CustomComparator

 use comparators
 use sorts_with_custom_comparator
 implicit none
 character(len=100), dimension(8) :: str
 integer :: i
 str = (/ "this", "is", "an", "array", "of", "strings", "to", "sort" /)
 call a_sort(str, my_compare)
 do i = 1, size(str)
    print *, trim(str(i))
 end do

end program CustomComparator</lang>

Groovy

The "custom comparator" is just a closure attached to the sort method invocation. <lang groovy>def strings = [ "Here", "are", "some", "sample", "strings", "to", "be", "sorted" ] strings.sort { x, y -> x.compareToIgnoreCase(y)} println strings</lang>

Output:

["are", "be", "Here", "sample", "some", "sorted", "strings", "to"]

Haskell

Works with: GHC

<lang haskell>import List import Char

mycmp s1 s2 = case compare (length s2) (length s1) of

                EQ -> compare (map toLower s1) (map toLower s2)
                x  -> x

strings = ["Here", "are", "some", "sample", "strings", "to", "be", "sorted"] sorted = sortBy mycmp strings</lang>

Alternate definition of mycmp using the Monoid instance for Ordering:

<lang haskell>import Data.Monoid mycmp s1 s2 = mappend (compare (length s2) (length s1))

                      (compare (map toLower s1) (map toLower s2))</lang>

J

Case-insensitivity is obtained using lower, a verb taken from Change string case. Standard utilities tolower or toupper may be substituted.

<lang j> mycmp=: 1 :'/:u'

   length_and_lex =: (-@:# ; lower)&>
   strings=: 'Here';'are';'some';'sample';'strings';'to';'be';'sorted'
   length_and_lex mycmp strings
+-------+------+------+----+----+---+--+--+
|strings|sample|sorted|Here|some|are|be|to|
+-------+------+------+----+----+---+--+--+</lang>

Java

Works with: Java version 1.5+

<lang java5>import java.util.Comparator; import java.util.Arrays;

public class Test {

 public static void main(String[] args) {
   String[] strings = {"Here", "are", "some", "sample", "strings", "to", "be", "sorted"};
   Arrays.sort(strings, new Comparator<String>() {
     public int compare(String s1, String s2) {
       int c = s2.length() - s1.length();
       if (c == 0)
         c = s1.compareToIgnoreCase(s2);
       return c;
     }
   });
   for (String s: strings)
     System.out.print(s + " ");
 }

}</lang>

JavaScript

<lang javascript>function lengthSorter(a, b) {

 var result = b.length - a.length;
 if (result == 0)
   result = a.localeCompare(b);
 return result;

}

var test = ["Here", "are", "some", "sample", "strings", "to", "be", "sorted"]; test.sort(lengthSorter); alert( test.join(' ') ); // strings sample sorted Here some are be to</lang>

Mathematica

We define a new function to give true or false if two elements are in order. After that we can simply use the built-in Sort with an ordering function: <lang Mathematica>

StringOrderQ[x_String, y_String] := 
 If[StringLength[x] > StringLength[y],
  True,
  If[StringLength[x] < StringLength[y],
   False,
   OrderedQ[{x, y}]
  ]
 ]
words={"on","sunday","sander","sifted","and","sorted","sambaa","for","a","second"};
Sort[words,StringOrderQ[#1,#2]&]

</lang> gives back: <lang Mathematica>

{sambaa,sander,second,sifted,sorted,sunday,and,for,on,a}

</lang>

MAXScript

fn myCmp str1 str2 =
(
    case of
    (
        (str1.count < str2.count):  1
        (str1.count > str2.count): -1
        default:(
                -- String compare is case sensitive, name compare isn't. Hence...
                str1 = str1 as name
                str2 = str2 as name
                case of
                (
                    (str1 > str2):  1
                    (str1 < str2): -1
                    default:        0
                )
                )
    )
)	

strList = #("Here", "are", "some", "sample", "strings", "to", "be", "sorted")
qSort strList myCmp
print strList

Nial

sort fork [=[tally first,tally last],up, >= [tally first,tally last]] ['Here', 'are', 'some', 'sample', 'strings', 'to', 'be', 'sorted']
=+-------+------+------+----+----+---+--+--+
=|strings|sample|sorted|Here|some|are|be|to|
=+-------+------+------+----+----+---+--+--+

Objective-C

Works with: GNUstep
Works with: Cocoa

<lang objc>#import <Foundation/Foundation.h>

@interface NSString (CustomComp) - (NSComparisonResult)my_compare: (id)obj; @end

  1. define esign(X) (((X)>0)?1:(((X)<0)?-1:0))

@implementation NSString (CustomComp) - (NSComparisonResult)my_compare: (id)obj {

 int l = esign((int)([self length] - [obj length]));
 switch(l) {
 case(NSOrderedDescending):
   return NSOrderedAscending; // reverse the ordering
 case(NSOrderedAscending):
   return NSOrderedDescending;
 case(NSOrderedSame):
   return [self caseInsensitiveCompare: obj];
 }
 return NSOrderedSame; // should never run this...

} @end

int main() {

 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 NSMutableArray *arr =
    [NSMutableArray
      arrayWithArray: [@"this is a set of strings to sort"
                        componentsSeparatedByString: @" "]
    ];
 [arr sortUsingSelector: @selector(my_compare:)];
 NSEnumerator *iter = [arr objectEnumerator];
 NSString *str;
 while( (str = [iter nextObject]) != nil )
 {
   NSLog(@"%@", str);
 }
 [pool release];
 return EXIT_SUCCESS;

}</lang>

This example can also be written using sort descriptors:

Works with: GNUstep
Works with: Cocoa

<lang objc>#import <Foundation/Foundation.h>

int main() {

 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 NSArray *strings = [@"Here are some sample strings to be sorted" componentsSeparatedByString:@" "];
 NSSortDescriptor *sd1 = [[NSSortDescriptor alloc] initWithKey:@"length" ascending:NO];
 NSSortDescriptor *sd2 = [[NSSortDescriptor alloc] initWithKey:@"lowercaseString" ascending:YES];
 NSArray *sortDescriptors = [NSArray arrayWithObjects:sd1, sd2, nil];
 [sd1 release];
 [sd2 release];
 NSArray *sorted = [strings sortedArrayUsingDescriptors:sortDescriptors];
 NSLog(@"%@", sorted);
 [pool release];
 return 0;

}</lang>

OCaml

<lang ocaml>let mycmp s1 s2 =

 if String.length s1 <> String.length s2 then
   compare (String.length s2) (String.length s1)
 else
   String.compare (String.lowercase s1) (String.lowercase s2)</lang>

List: <lang ocaml># let strings = ["Here"; "are"; "some"; "sample"; "strings"; "to"; "be"; "sorted"];; val strings : string list =

 ["Here"; "are"; "some"; "sample"; "strings"; "to"; "be"; "sorted"]
  1. List.sort mycmp strings;;

- : string list = ["strings"; "sample"; "sorted"; "Here"; "some"; "are"; "be"; "to"]</lang>

Array: <lang ocaml># let strings = [|"Here"; "are"; "some"; "sample"; "strings"; "to"; "be"; "sorted"|];; val strings : string array =

 [|"Here"; "are"; "some"; "sample"; "strings"; "to"; "be"; "sorted"|]
  1. Array.sort mycmp strings;;

- : unit = ()

  1. strings;;

- : string array = [|"strings"; "sample"; "sorted"; "Here"; "some"; "are"; "be"; "to"|]</lang>

Perl

Works with: Perl version 5.8.6

<lang perl>sub mycmp { length $b <=> length $a or lc $a cmp lc $b }

my @strings = ("Here", "are", "some", "sample", "strings", "to", "be", "sorted"); my @sorted = sort mycmp @strings;</lang>

Or inline: <lang perl>my @strings = qw/here are some sample strings to be sorted/; my @sorted = sort {length $b <=> length $a or lc $a cmp lc $b} @strings</lang>

Faster with a Schwartzian transform: <lang perl>my @strings = qw/here are some sample strings to be sorted/; my @sorted = map { $$_[0] }

            sort { $$a[1] <=> $$b[1] or $$a[2] cmp $$b[2] }
            map  { [ $_, length, lc ] }
            @strings;</lang>

PHP

Works with: PHP version 4.4.4 CLI

<lang php><?php function mycmp($s1, $s2) {

   if ($d = strlen($s2) - strlen($s1))
       return $d;
   return strcasecmp($s1, $s2);

}

$strings = array("Here", "are", "some", "sample", "strings", "to", "be", "sorted"); usort($strings, "mycmp"); ?></lang>

PL/I

Works with: IBM PL/I version 7.5

Platform: WIN <lang PL/I>

MRGEPKG: package exports(MERGESORT,MERGE,RMERGE);

DCL (T(4)) CHAR(20) VAR; /* scratch space of length N/2 */

MERGE: PROCEDURE (A,LA,B,LB,C,CMPFN);
   DECLARE (A(*),B(*),C(*)) CHAR(*) VAR;
   DECLARE (LA,LB) FIXED BIN(31) NONASGN;
   DECLARE (I,J,K) FIXED BIN(31);
   DECLARE CMPFN ENTRY(
          NONASGN CHAR(*) VAR,
          NONASGN CHAR(*) VAR)
          RETURNS (FIXED bin(31));
   
   I=1; J=1; K=1;
   DO WHILE ((I <= LA) & (J <= LB));
      IF CMPFN(A(I),B(J)) <= 0 THEN
         DO; C(K)=A(I); K=K+1; I=I+1; END;
      ELSE
         DO; C(K)=B(J); K=K+1; J=J+1; END;
   END;
   DO WHILE (I <= LA);
      C(K)=A(I); I=I+1; K=K+1;
   END;
   return;
END MERGE;

MERGESORT: PROCEDURE (A,N,CMPFN) RECURSIVE ;
     DECLARE (A(*))               CHAR(*) VAR;
     DECLARE N                    FIXED BINARY(31) NONASGN;
     DECLARE CMPFN                ENTRY(
          NONASGN CHAR(*) VAR,
          NONASGN CHAR(*) VAR)
                                  RETURNS (FIXED bin(31));
     DECLARE (M,I)                FIXED BINARY;
     DECLARE AMP1(N)              CHAR(20) VAR BASED(P);
     DECLARE P POINTER;
   IF (N=1) THEN RETURN;
   M = trunc((N+1)/2);
   IF M > 1 THEN CALL MERGESORT(A,M,CMPFN);
   P=ADDR(A(M+1)); 
   IF (N-M > 1) THEN CALL MERGESORT(AMP1,N-M,CMPFN);
   IF CMPFN(A(M),AMP1(1)) <= 0 THEN RETURN;
   DO I=1 to M; T(I)=A(I); END;
   CALL MERGE(T,M,AMP1,N-M,A,CMPFN);
END MERGESORT;
RMERGE: PROC OPTIONS(MAIN);
DCL I FIXED BIN(31);
DCL A(8) CHAR(20) VAR INIT("this","is","a","set","of","strings","to","sort");

MyCMP: PROCEDURE(A,B) RETURNS (FIXED BIN(31));
   DCL (A,B) CHAR(*) VAR NONASGN;
   DCL (I,J) FIXED BIN(31);
   I = length(trim(A)); J = length(trim(B));
   IF I < J THEN RETURN(+1);
   IF I > J THEN RETURN(-1);
   IF lowercase(A) < lowercase(B) THEN RETURN(-1);
   IF lowercase(A) > lowercase(B) THEN RETURN(+1);
   RETURN (0);
END MyCMP;

CALL MERGESORT(A,8,MyCMP);
DO I=1 TO 8;
   put edit (I,A(I)) (F(5),X(2),A(10)) skip;
END;

put skip;
END RMERGE;

</lang>

Pop11

lvars ls = ['Here' 'are' 'some' 'sample' 'strings' 'to' 'be' 'sorted'];
define compare(s1, s2);
lvars k = length(s2) - length(s1);
if k < 0 then
    return(true);
elseif k > 0 then
    return(false);
else
    return (alphabefore(uppertolower(s1), uppertolower(s2)));
endif;
enddefine;
syssort(ls, compare) -> ls;
NOTE: The definition of compare can also be written thus:
define compare(s1, s2);
 lvars
     l1 = length(s1),
     l2 = length(s2);
 l1 > l2 or (l1 == l2 and alphabefore(uppertolower(s1), uppertolower(s2)))
enddefine;

Python

Using a key function is usually more efficient than a comparator. We can take advantage of the fact that tuples are ordered first by the first element, then by the second, etc., to perform a sort on multiple criteria. <lang python> strings = "here are Some sample strings to be sorted".split()

def mykey(x):

   return -len(x), x.upper()

print sorted(strings, key=mykey) </lang>

To technically comply with this task, we can also use an actual comparator (cmp) function which will be called every time members of the original list are to be compared. Note that this feature has been removed from Python 3, so should no longer be used in new code. <lang python> def mycmp(s1, s2):

   return cmp(len(s2), len(s1)) or cmp(s1.upper(), s2.upper())

print sorted(strings, cmp=mycmp) </lang>

Ruby

Since Ruby 1.8.6 Enumerables have a "sort_by" method, taking a key block, which is more efficient than a comparator. We can take advantage of the fact that Arrays are ordered first by the first element, then by the second, etc., to perform a sort on multiple criteria.

<lang ruby>words = %w(Here are some sample strings to be sorted) p words.sort_by {|word| [-word.size, word.downcase]}</lang>

To technically comply with this task, we can also use an actual comparator block which will be called every time members of the original list are to be compared. <lang ruby>p words.sort {|a, b| d = b.size <=> a.size

                    d != 0 ? d : a.upcase <=> b.upcase}</lang>

Slate

<lang slate> define: #words -> #('here' 'are' 'some' 'sample' 'strings' 'to' 'sort' 'since' 'this' 'exercise' 'is' 'not' 'really' 'all' 'that' 'dumb' '(sorry)'). words sortBy: [| :first :second | (first lexicographicallyCompare: second) isNegative] </lang>

Smalltalk

<lang smalltalk>#('here' 'are' 'some' 'sample' 'strings' 'to' 'sort' 'since' 'this' 'exercise' 'is' 'not' 'really' 'all' 'that' 'dumb' '(sorry)' ) asSortedCollection

         sortBlock:
                    [:first :second | (second size = first size)
                                           ifFalse: [second size < first size]
                                           ifTrue: [first < second]]</lang>

Standard ML

List:

Works with: SML/NJ

<lang sml> fun mygt (s1, s2) =

 if size s1 <> size s2 then
   size s2 > size s1
 else
   String.map Char.toLower s1 > String.map Char.toLower s2

</lang>

<lang sml> - val strings = ["Here", "are", "some", "sample", "strings", "to", "be", "sorted"]; val strings = ["Here","are","some","sample","strings","to","be","sorted"]

 : string list

- ListMergeSort.sort mygt strings; val it = ["strings","sample","sorted","Here","some","are","be","to"]

 : string list

</lang>

Array:

Works with: SML/NJ

<lang sml> fun mycmp (s1, s2) =

 if size s1 <> size s2 then
   Int.compare (size s2, size s1)
 else
   String.compare (String.map Char.toLower s1, String.map Char.toLower s2)

</lang>

<lang sml> - val strings = Array.fromList ["Here", "are", "some", "sample", "strings", "to", "be", "sorted"]; val strings = [|"Here","are","some","sample","strings","to","be","sorted"|]

 : string array

- ArrayQSort.sort mycmp strings; val it = () : unit - strings; val it = [|"strings","sample","sorted","Here","some","are","be","to"|]

 : string array

</lang>

Tcl

<lang tcl>proc sorter {a b} {

   set la [string length $a]
   set lb [string length $b]
   if {$la < $lb} {
       return -1
   } elseif {$la > $lb} {
       return 1
   }
   return [string compare [string tolower $a] [string tolower $b]]

}

set strings {here are Some sample strings to be sorted} lsort -command sorter $strings ;# ==> be to are here Some sample sorted strings</lang>

Visual Basic .NET

<lang vbnet>Imports System

Module Sorting_Using_a_Custom_Comparator

   Function CustomComparator(ByVal x As String, ByVal y As String) As Integer
       Dim result As Integer
       result = y.Length - x.Length
       If result = 0 Then
           result = String.Compare(x, y, True)
       End If
       Return result
   End Function
   Sub Main()
       Dim strings As String() = {"test", "Zoom", "strings", "a"}
       Array.Sort(strings, New Comparison(Of String)(AddressOf CustomComparator))
   End Sub

End Module</lang>

Ursala

A standard library function, psort, takes a list of binary relational predicates and returns a function that uses them in order of decreasing priority to perform a sort. The less or equal length predicate (leql) and lexically less or equal predicate (lleq) are also standard library functions. This task is therefore easily dispatched as shown. <lang Ursala>

  1. import std
  2. show+

data = <'this','is','a','list','of','strings','to','be','sorted'>

example = psort<not leql,lleq+ ~* ~&K31K30piK26 letters> data</lang> The lleq library function is case sensitive, so it is composed with a function to convert the words to lower case on the fly (without destructively modifying them) in order to meet the task requirement of case insensitivity.

output:

strings
sorted
list
this
be
is
of
to
a