HP Forums
Sort Lists API: A collection of sort functions - Printable Version

+- HP Forums (https://www.hpmuseum.org/forum)
+-- Forum: HP Software Libraries (/forum-10.html)
+--- Forum: HP Prime Software Library (/forum-15.html)
+--- Thread: Sort Lists API: A collection of sort functions (/thread-11365.html)



Sort Lists API: A collection of sort functions - StephenG1CMZ - 09-08-2018 09:06 PM

A collection of Sort(List) functions (including some from the forum).
If you are looking for classic sorts (e.g. Bubble sort), look elsewhere (for now).


RE: Sorts API: A collection of sort functions - StephenG1CMZ - 09-08-2018 09:10 PM

Version 0.1 collects together the Sort functions previously contained in my List program (including Sortn from the forum), with minor implementation changes.
http://www.hpmuseum.org/forum/thread-9411.html
Requires List which should be compiled first.
Code:

Code

 LOCAL CRID:="Sorts API V0.1 © 2018 StephenG1CMZ";
 LOCAL MORETEXT:="A collection of sort routines brought to you by StephenG1CMZ,\n with some from the forum.";
 LOCAL MN:="Sorts.";//Name

 //IMPORT({List}); //Required

 LOCAL TYPELST:=TYPE({});
 LOCAL TYPEFLOAT:=TYPE(3.1);
 LOCAL TYPEINT:=TYPE(#3);
 LOCAL TYPESTR:=TYPE(" ");

 //Customise
 EXPORT SortableTypes:={TYPEFLOAT,TYPEINT,TYPESTR};
 LOCAL UNK0:=0;//EMPTY IS UNKNOWN,DEFAULT FALSE
 LOCAL UNK1:=1;//EMPTY IS UNKNOWN,DEFAULT TRUE
 //LOCAL SL:=1;
 //NB To test: sort >1 item
 //End

 //Forward
 IsSortablePortable(LST);
 SortL(LST);
 SortN(LST,NN);
 LOCAL NL:="\n";

 LOCAL ListANS;//OUTPUT LIST(WHEN NOT RETURNED)

 //ERR 
 LOCAL ListErrK:=1;
 LOCAL PyErrK:=3;
 EXPORT ListLastError:=0;
 LOCAL ERRKIND:={"","Error","","Py Error"};

 EXPORT EL:={
  "(/0) DivideBy0",
  "IndexOutofBoundsException",
  "ListIsEmptyError",
  "ListIsFullError",
  "ListSortError",
  "ListStatisticsError",
  "ItemNotFoundError",
  "ValueError"
 };
 //ERRNO IS ARBITRARY:INDEXES ERRLST
 EXPORT DivBy0Error:=1;
 LOCAL IndexOutOfBoundsException:=2;//List J
 EXPORT ListIsEmptyError:=3;
 LOCAL ListIsFullError:=4;//UNUSED YET
 LOCAL SortError:=5;
 EXPORT ListStatisticsError:=6;
 EXPORT ItemNotFoundError:=7;//List Py
 EXPORT ValueError:=8; // Py
 
 EXPORT ABOUT()
 BEGIN
  MSGBOX(CRID);
  MSGBOX(MORETEXT);
 END;

 TBD()
 BEGIN
  MSGBOX(MN+"TBD");
 END;

 EXPORT IsSortable(LST)
 //For now use Portable
 //Later: as SORT
 BEGIN
  RETURN IsSortablePortable(LST);
 END;

 EXPORT IsSortablePortable(LST)
 //0.Is parameter a list
 //1.Is TYPE of contents OF ORDERABLE DATA
 //2.Is SORTL implemented on that type yet
 //NOTE:
 //IsSORTABLE({Real})=1 AND IsSORTABLE({INT})=1 AND IsSORTABLE({string})=1 but
 //do not assume SORT({mixed}) will deliver your expectations
 //NB The current algorithm reports {1,"4"} as sortable
 //But native sort wont
 //The Portable variant assumes strings and numerics are sortable.
 BEGIN
  IF TYPE(LST)==TYPELST THEN
   IF SIZE(LST) THEN
    RETURN ListIsTYPE(LST,SortableTypes);
   END;
   RETURN UNK0;//EMPTY
  END;
  RETURN 0;//NOT LIST:CANNOT BE SORTED
 END;

 EXPORT IsSortedEQ(LST)
 //Tells whether a list is sorted...inefficiently
 //By sorting it and checking equality
 //(Useful for testing)
 BEGIN
  ListANS:=SortL(LST);
  RETURN EQ(ListANS,LST);
 END;
 
 EXPORT IsSorted(LST)
 //Looping until 1st descending will/may be quicker TBD
 BEGIN
  RETURN IsSortedEQ(LST);
 END;

 EXPORT SortByKey(SORTS,KeyNum)
 //Sort lists by list number KeyNum (with some input guards)
 BEGIN
  IF 0<KeyNum≤SIZE(SORTS) THEN
   IF SIZE(SORTS)>1 AND SORTS(1)≠{} AND SORTS(2)≠{} THEN
    RETURN SortN(SORTS,KeyNum);
   END;
  ELSE
   //Potential:not all checked
   //List small, not containing lists, key out of range, key list unsortable
   RAISE(MN+"SortByKey",EL,SortError,KeyNum,ListErrK);
  END;
  RETURN SORTS;
 END;

 EXPORT SortByOccurrences(LST)
 //Returns {LSTV,LSTF} sorted by frequency of occurrence
 //reverse so most popular is 1st and index is approx rank 
 BEGIN
  TBD();
  //ListANS:=ListOCCURRENCES(LST);
  RETURN REVERSE(SortByKey(ListANS,2));
 END;

 EXPORT SortL(LST)
 //This implementation uses native SORT
 BEGIN
  IF TYPE(LST)≠TYPELST THEN 
   RAISE(MN+"SortL",EL,SortError,"",ListErrK);
  END;
  RETURN SORT(LST);
 END;

 EXPORT SortN(list,n)
 // From http://www.hpmuseum.org/forum/thread-6179.html?highlight=sort+two+lists
 //Call via ListSORTBYKEY to guard parameters...or call directly with good inputs 
 BEGIN
  LOCAL li,ma;
  ma:=list2mat(list) ;
  li:=SORT(MAKELIST(mat2list(col(ma,I)),I,1,colDim(ma)),n);
  RETURN MAKELIST(mat2list(col(list2mat(li),I)),I,1,rowDim(ma));
 //For example:
 //SORTN({{3,2,1},{15,20,18}},1);// -> {{1,2,3},{18,20,15}}
 //SORTN({{3,2,1},{15,20,18},{32,35,27}},1);// -> {{1,2,3},{18,20,15},{27,35,32}}
 END;

 EXPORT SortsVERSION()
 BEGIN
  RETURN CRID;
 END;

 
 EXPORT Pyreverse(LST)
 //Python analogue
 BEGIN
  RETURN REVERSE(LST);
 END;

EXPORT Pysort(LST,KeyFunc,RReverse)
 //Python analogue SORT
 //TBD: KeyFunc: Selects sort key from item
 BEGIN
  IF TYPE(KeyFunc)==TYPEFLOAT AND KeyFunc==0 THEN
   //0=None=NO FUNC
  ELSE
   TBD();
   RAISE(MN+"Pysort",EL,ValueError,"",1);//TBD
  END;
  RETURN IFTE(RReverse,SORT(Pyreverse(LST)),SORT(LST));
 END;

EXPORT ListPuzzles()
 //SEE http://www.hpmuseum.org/forum/thread-8209.html?highlight=challenge
 BEGIN
  LOCAL VR;
  LOCAL LST:=MAKELIST("",VR,1,5);//40
  LST(2):="31. ListOCCURRENCESWITHSORT";
  CHOOSE(VR,MN+"Puzzles (See thread)",LST);
 END;

EXPORT SortSeeAlso ()
 BEGIN
  LOCAL KK;
  LOCAL CatFuns:={
   "REVERSE",
   "reverse",
   "revlist",
   "SORT",
   "sort"
   };
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,MN+" Relevant Cat Functions",CatFuns)

 END;
 
 EXPORT SortsExamples()
 //In real use, use XXX:=Sort...()
 BEGIN
  LOCAL LL:={1,2,3,4,5,6,7,8,9};
  PRINT();
  PRINT(SortsVERSION);
  PRINT("Is");
  PRINT(IsSortable(0));
  PRINT(IsSortable({})); 
  PRINT(IsSortable(LL));
  //PRINT(IsSortable(LL+{3.1}));

  PRINT(IsSorted(LL)); 
  //PRINT(ListIsTYPE({3.4},1-1));
  PRINT("Sort");
  //SortByABS
  //SortByKey
  //SortByOccurrences
  //TBD PRINT(SortByOccurrences({1,2,2,3,3,3}));
  //SortL
  PRINT(SortL(LL));
  //SortN
  PRINT(SortN({{3,2,1},{15,20,18}},1));// -> {{1,2,3},{18,20,15}}
  PRINT(SortN({{3,2,1},{15,20,18},{32,35,27}},1));// -> {{1,2,3},{18,20,15},{27,35,32}}
 
  PRINT("Exampled");
  //RETURN 0; 
 END;

 EXPORT SORTS()
 BEGIN
  ABOUT();
  //SortExamples();
 END;

Version 0.2 is reworked to minimise the need for my "List" program.
I had hoped it would now only be needed for error handling, but in fact there is still a dependency on ListIsTYPE too..
New routines ReverseLOL, SortByCount, SortByABS.
Code:


 LOCAL CRID:="Sorts API V0.2 © 2018 StephenG1CMZ";
 LOCAL MORETEXT:="A collection of sort routines brought to you by StephenG1CMZ,\n with some from the forum.";
 LOCAL MN:="Sorts.";//Name
 //Also includes REVERSE functions

 //IMPORT({List}); //for error handling

 LOCAL TYPELST:=TYPE({});
 LOCAL TYPEFLOAT:=TYPE(3.1);
 LOCAL TYPEINT:=TYPE(#3);
 LOCAL TYPESTR:=TYPE(" ");

 //Customise
 EXPORT SortableTypes:={TYPEFLOAT,TYPEINT,TYPESTR};
 LOCAL UNK0:=0;//EMPTY IS UNKNOWN,DEFAULT FALSE
 LOCAL UNK1:=1;//EMPTY IS UNKNOWN,DEFAULT TRUE
 //LOCAL SL:=1;
 //NB To test: sort >1 item
 //End

 //Forward
 IsSortablePortable(LST);
 SortByKeyTBD(SORTS,Keynum);
 SortL(LST);
 SortN(LST,NN);
 LOCAL NL:="\n";

 LOCAL ListANS;//OUTPUT LIST(WHEN NOT RETURNED)

 //ERR 
 LOCAL ListErrK:=1;
 LOCAL PyErrK:=3;
 EXPORT ListLastError:=0;
 LOCAL ERRKIND:={"","Error","","Py Error"};

 EXPORT EL:={
  "(/0) DivideBy0",
  "IndexOutofBoundsException",
  "ListIsEmptyError",
  "ListIsFullError",
  "ListSortError",
  "ListStatisticsError",
  "ItemNotFoundError",
  "ValueError"
 };
 //ERRNO IS ARBITRARY:INDEXES ERRLST
 EXPORT DivBy0Error:=1;
 LOCAL IndexOutOfBoundsException:=2;//List J
 EXPORT ListIsEmptyError:=3;
 LOCAL ListIsFullError:=4;//UNUSED YET
 LOCAL SortError:=5;
 EXPORT ListStatisticsError:=6;
 EXPORT ItemNotFoundError:=7;//List Py
 EXPORT ValueError:=8; // Py
 
 EXPORT ABOUT()
 BEGIN
  MSGBOX(CRID);
  MSGBOX(MORETEXT);
 END;

 TBD()
 BEGIN
  MSGBOX(MN+"TBD");
 END;

 EXPORT IsSortable(LST)
 //For now use Portable
 //Later: as native SORT
 BEGIN
  RETURN IsSortablePortable(LST);
 END;

 EXPORT IsSortablePortable(LST)
 //0.Is parameter a list
 //1.Is TYPE of contents OF ORDERABLE DATA
 //2.Is SORTL implemented on that type yet
 //NOTE:
 //IsSORTABLE({Real})=1 AND IsSORTABLE({INT})=1 AND IsSORTABLE({string})=1 but
 //do not assume SORT({mixed}) will deliver your expectations
 //NB The current algorithm reports {1,"4"} as sortable
 //But native sort wont
 //The Portable variant assumes strings and numerics are sortable.
 BEGIN
  IF TYPE(LST)==TYPELST THEN
   IF SIZE(LST) THEN
    RETURN ListIsTYPE(LST,SortableTypes);
   END;
   RETURN UNK0;//EMPTY
  END;
  RETURN 0;//NOT LIST:CANNOT BE SORTED
 END;

 EXPORT IsSortedEQ(LST)
 //Tells whether a list is sorted...inefficiently
 //By sorting it and checking equality
 //(Useful for testing)
 BEGIN
  ListANS:=SortL(LST);
  RETURN EQ(ListANS,LST);
 END;
 
 EXPORT IsSorted(LST)
 //Looping until 1st descending will/may be quicker TBD
 BEGIN
  RETURN IsSortedEQ(LST);
 END;

 EXPORT ReverseLOL(LSTS)
 //Reverse a list of lists
 //EG {{1,2},{3,4}} -> {{2,1},{4,3}}
 //NONRECURSIVE:TOP LISTS ONLY
 //ALL LISTS MUST BE REVERSIBLE
 BEGIN
  LOCAL II;
  ListANS:={};
  IF SIZE(LSTS) THEN
   //REVERSE EACH LST
   FOR II FROM 1 TO SIZE(LSTS) DO
    ListANS(II):=REVERSE(LSTS(II));
   END;//FOR  
  END;
  RETURN ListANS;
 END;

 EXPORT SortByABS(LST)
 BEGIN
  LOCAL TMP:={};
  IF SIZE(LST) THEN
   TMP:=SortN({ABS(LST),SIGN(LST)},1);
   RETURN TMP(1)*TMP(2);
  END;
  RETURN {};
 END;

 EXPORT SortByCount(LSTS,Keynum)
 //LSTS is {LSTV,LSTF} as returned by
 //ListOCCURRENCES(LST);
 //but additional fields are allowed
 //Returns {LSTV,LSTF} sorted by frequency of occurrence 
 //EG {{1,2,3},{10,30,20}} -> {{2,3,1},{10,20,30}}
 BEGIN
   IF SIZE(LSTS)≥Keynum THEN
    IF SIZE(LSTS(1))>1 AND SIZE(LSTS(Keynum))>1 THEN
     RETURN SortN(LSTS,K);
    END;
   END;
  RETURN {};
  //To reverse sequence call ReverseLOLS()
 END;
 //These routines are similar
 //Why does one fail TBD
 EXPORT SortByKeyTBD(LSTS,KeyNum)
 //Sort lists by list number KeyNum (with some input guards)
 //Hint: If this gives a data type error call SORTN directly (WHY?) 
 BEGIN
  IF 0<KeyNum≤SIZE(LSTS) AND SIZE(LSTS)>1 THEN
   IF LSTS(1)≠{} AND LSTS(2)≠{} THEN
    RETURN SortN(LSTS,KeyNum);
   END;
  ELSE
   //Potential:not all checked
   //List small, not containing lists, key out of range, key list unsortable
   RAISE(MN+"SortByKey",EL,SortError,KeyNum,ListErrK);
  END;
  RETURN {};
 END;

 EXPORT SortL(LST)
 //This implementation uses native SORT
 BEGIN
  IF TYPE(LST)≠TYPELST THEN 
   RAISE(MN+"SortL",EL,SortError,"",ListErrK);
  END;
  RETURN SORT(LST);
 END;

 EXPORT SortN(list,n)
 // From http://www.hpmuseum.org/forum/thread-6179.html?highlight=sort+two+lists
 //Call via ListSORTBYKEY to guard parameters...or call directly with good inputs 
 BEGIN
  LOCAL li,ma;
  ma:=list2mat(list) ;
  li:=SORT(MAKELIST(mat2list(col(ma,I)),I,1,colDim(ma)),n);
  RETURN MAKELIST(mat2list(col(list2mat(li),I)),I,1,rowDim(ma));
 //For example:
 //SORTN({{3,2,1},{15,20,18}},1);// -> {{1,2,3},{18,20,15}}
 //SORTN({{3,2,1},{15,20,18},{32,35,27}},1);// -> {{1,2,3},{18,20,15},{27,35,32}}
 END;

 EXPORT SortsVERSION()
 BEGIN
  RETURN CRID;
 END;

 
 EXPORT Pyreverse(LST)
 //Python analogue
 BEGIN
  RETURN REVERSE(LST);
 END;

EXPORT Pysort(LST,KeyFunc,RReverse)
 //Python analogue SORT
 //TBD: KeyFunc: Selects sort key from item
 BEGIN
  IF TYPE(KeyFunc)==TYPEFLOAT AND KeyFunc==0 THEN
   //0=None=NO FUNC
  ELSE
   TBD();
   RAISE(MN+"Pysort",EL,ValueError,"",1);//TBD
  END;
  RETURN IFTE(RReverse,SORT(Pyreverse(LST)),SORT(LST));
 END;

EXPORT ListPuzzles()
 //SEE http://www.hpmuseum.org/forum/thread-8209.html?highlight=challenge
 BEGIN
  LOCAL VR;
  LOCAL LST:=MAKELIST("",VR,1,5);//40
  LST(2):="31. ListOCCURRENCESWITHSORT";
  CHOOSE(VR,MN+"Puzzles (See thread)",LST);
 END;

EXPORT SortSeeAlso ()
 BEGIN
  LOCAL KK;
  LOCAL CatFuns:={
   "REVERSE",
   "reverse",
   "revlist (slower)",
   "SORT",
   "sort"
   };
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,MN+" Relevant Cat Functions",CatFuns)

 END;
 
 EXPORT SortsExamples()
 //In real use, use XXX:=Sort...()
 BEGIN
  LOCAL LL:={1,2,3,4,5,6,7,8,9};
  PRINT();
  PRINT(SortsVERSION);

  PRINT("Is");
  PRINT(IsSortable(0));
  PRINT(IsSortable({})); 
  PRINT(IsSortable(LL));
  PRINT(IsSortablePortable(LL));
  

  PRINT(IsSorted(LL)); 
  PRINT(IsSortedEQ(LL));
 
  PRINT("Reverse");

  PRINT(ReverseLOL({{1,2},{3,4},{5,6}}));
 
  PRINT("Sort");

  //SortByABS
  PRINT(SortByABS({1,2,3,−2})); // -> {1,2,−2,3}
 
  //SortByCount
  PRINT(SortByCount({{1,2,3},{10,30,20}},2)); // -> {{2,3,1},{10,20,30}} 
  //SortByKey

  //SortL
  PRINT(SortL(LL));

  //SortN
  PRINT(SortN({{3,2,1},{15,20,18}},1));// -> {{1,2,3},{18,20,15}}
  PRINT(SortN({{3,2,1},{15,20,18},{32,35,27}},1));// -> {{1,2,3},{18,20,15},{27,35,32}}
  
  //SortByOccurrences
  PRINT(SortByCount({{1,2,3},{1,22,3}},2));
  PRINT(ReverseLOL(SortByCount({{1,2,3},{1,22,3}},2)));
 
  PRINT("Py");
  PRINT(Pyreverse({1,2,3}));
  PRINT(Pysort({1,22,3},0,0));
  PRINT("Exampled");
  //RETURN 0; 
 END;

 EXPORT SORTS()
 BEGIN
  ABOUT();
  //SortExamples();
 END;



RE: Sort Lists API: A collection of sort functions - StephenG1CMZ - 09-15-2018 10:52 PM

Version 0.3 now implements Pysort and fixes some bugs.

Code:


 LOCAL CRID:="SortL API V0.3 © 2018 StephenG1CMZ";
 LOCAL MORETEXT:="A collection of Sort(List) routines brought to you by StephenG1CMZ,\n with some from the forum.";
 LOCAL MN:="SortL.";//Name
 //Also includes REVERSE functions

 //IMPORT({List}); //Required

 LOCAL TYPELST:=TYPE({});
 LOCAL TYPEFLOAT:=TYPE(3.1);
 LOCAL TYPEINT:=TYPE(#3);
 LOCAL TYPESTR:=TYPE(" ");

 //Customise
 EXPORT SortableTypes:={TYPEFLOAT,TYPEINT,TYPESTR};
 LOCAL UNK0:=0;//EMPTY IS UNKNOWN,DEFAULT FALSE
 LOCAL UNK1:=1;//EMPTY IS UNKNOWN,DEFAULT TRUE
 //LOCAL SL:=1;
 //NB To test: sort >1 item
 //End

 //Forward
 IsSortablePortable(LST);
 SortByKey(SORTL,Keynum);
 SortByKeyTBD(SORTL,Keynum);
 SortLST(LST);
 SortN(LST,NN);
 LOCAL NL:="\n";

 LOCAL ListANS;//OUTPUT LIST(WHEN NOT RETURNED)

 //ERR 
 LOCAL ListErrK:=1;
 LOCAL PyErrK:=3;
 EXPORT ListLastError:=0;
 LOCAL ERRKIND:={"","Error","","Py Error"};

 EXPORT EL:={
  "(/0) DivideBy0",
  "IndexOutofBoundsException",
  "ListIsEmptyError",
  "ListIsFullError",
  "ListSortError",
  "ListStatisticsError",
  "ItemNotFoundError",
  "ValueError"
 };
 //ERRNO IS ARBITRARY:INDEXES ERRLST
 EXPORT DivBy0Error:=1;
 LOCAL IndexOutOfBoundsException:=2;//List J
 EXPORT ListIsEmptyError:=3;
 LOCAL ListIsFullError:=4;//UNUSED YET
 LOCAL SortError:=5;
 EXPORT ListStatisticsError:=6;
 EXPORT ItemNotFoundError:=7;//List Py
 EXPORT ValueError:=8; // Py
 
 EXPORT ABOUT()
 BEGIN
  MSGBOX(CRID);
  MSGBOX(MORETEXT);
 END;

 TBD()
 BEGIN
  MSGBOX(MN+"TBD");
 END;

EXPORT RAISE(MN,ERRLST,ERR,CULPRIT,SEVERITY)
 BEGIN
 END;
 
 EXPORT IsSortable(LST)
 //For now use Portable
 //Later: as native SORT
 BEGIN
  RETURN IsSortablePortable(LST);
 END;

 EXPORT IsSortablePortable(LST)
 //0.Is parameter a list
 //1.Is TYPE of contents OF ORDERABLE DATA
 //2.Is SORTL implemented on that type yet
 //NOTE:
 //IsSORTABLE({Real})=1 AND IsSORTABLE({INT})=1 AND IsSORTABLE({string})=1 but
 //do not assume SORT({mixed}) will deliver your expectations
 //NB The current algorithm reports {1,"4"} as sortable
 //But native sort wont
 //The Portable variant assumes strings and numerics are sortable.
 BEGIN
  IF TYPE(LST)==TYPELST THEN
   IF SIZE(LST) THEN
    RETURN ListIsTYPE(LST,SortableTypes);
   END;
   RETURN UNK0;//EMPTY
  END;
  RETURN 0;//NOT LIST:CANNOT BE SORTED
 END;

 EXPORT IsSortedEQ(LST)
 //Tells whether a list is sorted...inefficiently
 //By sorting it and checking equality
 //(Useful for testing)
 BEGIN
  ListANS:=SortLST(LST);
  RETURN EQ(ListANS,LST);
 END;
 
 EXPORT IsSorted(LST)
 //Looping until 1st descending will/may be quicker TBD
 BEGIN
  RETURN IsSortedEQ(LST);
 END;

 EXPORT ReverseLOL(LSTS)
 //Reverse a list of lists
 //EG {{1,2},{3,4}} -> {{2,1},{4,3}}
 //NONRECURSIVE:2ND LEVEL LISTS ONLY
 //ALL LISTS MUST BE REVERSIBLE
 BEGIN
  LOCAL II;
  ListANS:={};
  IF SIZE(LSTS) THEN
   //REVERSE EACH LST
   FOR II FROM 1 TO SIZE(LSTS) DO
    ListANS(II):=REVERSE(LSTS(II));
   END;//FOR  
  END;
  RETURN ListANS;
 END;

 EXPORT SortByABS(LST)
 BEGIN
  LOCAL TMP:={};
  IF SIZE(LST) THEN
   TMP:=SortN({ABS(LST),SIGN(LST)},1);
   RETURN TMP(1)*TMP(2);
  END;
  RETURN {};
 END;

 //The following could return just the valuesO
 //or Values and counts in 2 lists
 //Whichis preferred?

 EXPORT SortByCounts(LST)
 //Returns {LSTV,LSTF} sorted by frequency of occurrence 
 //EG {{1,2,3},{10,30,20}} -> {{2,3,1},{10,20,30}}
 
 BEGIN
  ListANS:=ListCOUNTS(LST);//To omit this step, use SortByKey directly
  RETURN SortByKey(ListANS,2);
 END;

 EXPORT SortByKey(LSTS,Keynum)
 //LSTS is {LSTV,LSTF} as returned by
 //ListCOUNTS(LST);
 //but additional fields are allowed
 //Returns {LSTV,LSTF} sorted by frequency of occurrence 
 //EG {{1,2,3},{10,30,20}} -> {{2,3,1},{10,20,30}}
 
 BEGIN
   IF SIZE(LSTS)≥Keynum THEN
    IF SIZE(LSTS(1))>1 AND SIZE(LSTS(Keynum))>1 THEN
     RETURN SortN(LSTS,K);
    END;
   END;
  RETURN {};
  //To reverse sequence call ReverseLOLS()
 END;
 //These routines are similar
 //Why does one fail TBD
 EXPORT SortByKeyTBD(LSTS,KeyNum)
 //Sort lists by list number KeyNum (with some input guards)
 //Hint: If this gives a data type error call SORTN directly (WHY?) 
 BEGIN
  IF 0<KeyNum≤SIZE(LSTS) AND SIZE(LSTS)>1 THEN
   IF LSTS(1)≠{} AND LSTS(2)≠{} THEN
    RETURN SortN(LSTS,KeyNum);
   END;
  ELSE
   //Potential:not all checked
   //List small, not containing lists, key out of range, key list unsortable
   RAISE(MN+"SortByKey",EL,SortError,KeyNum,ListErrK);
  END;
  RETURN {};
 END;

 EXPORT SortLST(LST)
 //This implementation uses native SORT
 BEGIN
  IF TYPE(LST)≠TYPELST THEN 
   RAISE(MN+"SortL",EL,SortError,"",ListErrK);
  END;
  RETURN SORT(LST);
 END;

 EXPORT SortN(list,n)
 // From http://www.hpmuseum.org/forum/thread-6179.html?highlight=sort+two+lists
 //Call via ListSORTBYKEY to guard parameters...or call directly with good inputs 
 BEGIN
  LOCAL li,ma;
  ma:=list2mat(list) ;
  li:=SORT(MAKELIST(mat2list(col(ma,I)),I,1,colDim(ma)),n);
  RETURN MAKELIST(mat2list(col(list2mat(li),I)),I,1,rowDim(ma));
 //For example:
 //SORTN({{3,2,1},{15,20,18}},1);// -> {{1,2,3},{18,20,15}}
 //SORTN({{3,2,1},{15,20,18},{32,35,27}},1);// -> {{1,2,3},{18,20,15},{27,35,32}}
 END;

 EXPORT SortsVERSION()
 BEGIN
  RETURN CRID;
 END;

 
 EXPORT Pyreverse(LST)
 //Python analogue
 BEGIN
  RETURN REVERSE(LST);
 END;

EXPORT Pysort(LST,KeyFunc,RReverse)
 //Python analogue SORT
 //PyOpt KeyFunc: STRING EG "ABS" (NULL=NONE)
 //PyOpt PRReverse BOOL
 BEGIN
  LOCAL TMP;
  IF KeyFunc=="" THEN
   ListANS:=SORT(LST);
   RETURN IFTE(RReverse,Pyreverse(ListANS),ListANS);
  END;
  TMP:=EXPR(KeyFunc+"(LST)");
  ListANS:=SortN({LST,TMP},2);
  RETURN IFTE(RReverse,Pyreverse(ListANS(1)),ListANS(1)); 
 END;

EXPORT ListPuzzles()
 //SEE http://www.hpmuseum.org/forum/thread-8209.html?highlight=challenge
 BEGIN
  LOCAL VR;
  LOCAL LST:=MAKELIST("",VR,1,5);//40
  LST(2):="31. ListOCCURRENCESWITHSORT";
  CHOOSE(VR,MN+"Puzzles (See thread)",LST);
 END;

EXPORT SortSeeAlso ()
 BEGIN
  LOCAL KK;
  LOCAL CatFuns:={
   "REVERSE",
   "reverse",
   "revlist (slower)",
   "SORT",
   "sort"
   };
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,MN+" Relevant Cat Functions",CatFuns)

 END;
 
 EXPORT SortsExamples()
 //In real use, use XXX:=Sort...()
 BEGIN
  LOCAL LL:={1,2,3,4,5,6,7,8,9};
  PRINT();
  PRINT(SortsVERSION);

  PRINT("Is");
  PRINT(IsSortable(0));
  PRINT(IsSortable({})); 
  PRINT(IsSortable(LL));
  PRINT(IsSortablePortable(LL));
  

  PRINT(IsSorted(LL)); 
  PRINT(IsSortedEQ(LL));
 
  PRINT("Reverse");

  PRINT(ReverseLOL({{1,2},{3,4},{5,6}}));
 
  PRINT("Sort");

  //SortByABS
  PRINT(SortByABS({1,2,3,−2})); // -> {1,2,−2,3}
 
  //SortByCounts
  PRINT(SortByCounts({1,2,3,2,3,3})); // -> {{1,2,3},{1,2,3}} 
  //SortByKey
  PRINT(SortByKey({{1,2,3},{10,30,20}},2)); //-> {{1,3,2},{10,20,30}}
  PRINT(SortByKey({{1,2,3},{1,22,3}},2));
  PRINT(ReverseLOL(SortByKey({{1,2,3},{1,22,3}},2)));

  //SortL
  PRINT(SortLST(LL));

  //SortN
  PRINT(SortN({{3,2,1},{15,20,18}},1));// -> {{1,2,3},{18,20,15}}
  PRINT(SortN({{3,2,1},{15,20,18},{32,35,27}},1));// -> {{1,2,3},{18,20,15},{27,35,32}}
  
  PRINT("Py");
  PRINT(Pyreverse({1,2,3}));
  PRINT(Pysort({1,22,3},"",0));
  PRINT(Pysort({1,22,3},"ABS",0));
  PRINT("Exampled");
  //RETURN 0; 
 END;

 EXPORT SORTL()
 BEGIN
  ABOUT();
  //SortExamples();
 END;



RE: Sort Lists API: A collection of sort functions - StephenG1CMZ - 09-27-2018 09:19 PM

Version 0.4C implements IsSortableNative to track the functionality of the native SORT.
Some functions are unexported to minimise global effects.
(0.4C Corrects minor errors in 0.4,0.4A and 0.4B)
Code:

LOCAL CRID:="SortL API V0.4C © 2018 StephenG1CMZ";
 LOCAL MORETEXT:="A collection of Sort(List) routines brought to you by StephenG1CMZ,\n with some from the forum.";
 LOCAL MN:="SortL.";//Name
 //Also includes REVERSE functions
 //NB REVERSE REVERSES A LIST (WHICH MIGHT HAVE BEEN SORTED)
 //(IT DOES NOT OF ITSELF REVERSE-SORT DESPITE BEING IN THIS SORTL PROGRAM)


 //IMPORT({List}); //Required
 //Some exportables (ex) omitted to minimise global impact
 //Customise
 EXPORT SortableNumericTypes:={TYPEFLOAT,TYPEINT};
 LOCAL UNK0:=0;//EMPTY IS UNKNOWN,DEFAULT FALSE
 LOCAL UNK1:=1;//EMPTY IS UNKNOWN,DEFAULT TRUE
 //LOCAL SL:=1;
 //NB To test: sort >1 item
 //End

 //Forward
 IsSortablePortable(LST);
 SortByKey(SORTL,Keynum);
 SortByKeyTBD(SORTL,Keynum);
 SortLST(LST);
 SortN(LST,NN);
 LOCAL NL:="\n";

 //ERR 
 LOCAL ListErrK:=1;
 LOCAL PyErrK:=3;
 LOCAL ERRKIND:={"","Error","","Py Error"};

 EXPORT EL:={
  "(/0) DivideBy0",
  "IndexOutofBoundsException",
  "ListIsEmptyError",
  "ListIsFullError",
  "ListSortError",
  "ListStatisticsError",
  "ItemNotFoundError",
  "ValueError"
 };
 //ERRNO IS ARBITRARY:INDEXES ERRLST
 EXPORT DivBy0Error:=1;
 LOCAL IndexOutOfBoundsException:=2;//List J
 EXPORT ListIsEmptyError:=3;
 LOCAL ListIsFullError:=4;//UNUSED YET
 LOCAL SortError:=5;
 EXPORT ListStatisticsError:=6;
 EXPORT ItemNotFoundError:=7;//List Py
 EXPORT ValueError:=8; // Py
 
 EXPORT ABOUT()
 BEGIN
  MSGBOX(CRID);
  MSGBOX(MORETEXT);
 END;

 TBD()
 BEGIN
  MSGBOX(MN+"TBD");
 END;
 
 IsSortable(LST) //ex
 //For now use Portable
 //Later: as native SORT
 BEGIN
  RETURN IsSortablePortable(LST);
 END;

 EXPORT IsSortableNative(LST)
 //Checks whether the contents of LST are natively sortable
 //Returns 1 TYPESTR only
 //Returns 1 SortableNumeric
 //NB Lists and keys can be sorted but lists alone no
 BEGIN
  LOCAL TP;
  IF SIZE(LST) THEN
   TP:=TYPE(LST(1));
   CASE
    IF TP==TYPESTR THEN 
     RETURN ListIsTYPE(LST,TYPESTR);
    END;
    IF POS(SortableNumericTypes,TP) THEN 
     RETURN ListIsTYPE(LST,SortableNumericTypes);
    END;
    DEFAULT
     RETURN 0;//UNSORTABLE
   END;//CASE
  END;
  RETURN 1;//EMPTY INDETERMINATE
 END;

 EXPORT IsSortablePortable(LST)
 //0.Is parameter a list
 //1.Is TYPE of contents OF ORDERABLE DATA
 //2.Is SORTL implemented on that type yet
 //NOTE:
 //IsSORTABLE({Real})=1 AND IsSORTABLE({INT})=1 AND IsSORTABLE({string})=1 but
 //do not assume SORT({mixed}) will deliver your expectations
 //NB The current algorithm reports {1,"4"} as sortable
 //But native sort wont
 //The Portable variant assumes strings and numerics are sortable.
 BEGIN
  LOCAL SortableTypes:=CONCAT(SortableNumericTypes,TYPESTR);
  IF TYPE(LST)==TYPELST THEN
   IF SIZE(LST) THEN
    RETURN ListIsTYPE(LST,SortableTypes);
   END;
   RETURN UNK0;//EMPTY
  END;
  RETURN 0;//NOT LIST:CANNOT BE SORTED
 END;

 IsSortedEQ(LST) //EX
 //Tells whether a list is sorted...inefficiently
 //By sorting it and checking equality
 //(Useful for testing)
 BEGIN
  ListANS:=SortLST(LST);
  RETURN EQ(ListANS,LST);
 END;
 
 EXPORT IsSorted(LST)
 //Looping until 1st descending will/may be quicker TBD
 BEGIN
  RETURN IsSortedEQ(LST);
 END;

 EXPORT ReverseLOL(LSTS)
 //Reverse a list of lists
 //EG {{1,2},{3,4}} -> {{2,1},{4,3}}
 //NONRECURSIVE:2ND LEVEL LISTS ONLY
 //ALL LISTS MUST BE REVERSIBLE
 BEGIN
  LOCAL II;
  ListANS:={};
  IF SIZE(LSTS) THEN
   //REVERSE EACH LST
   FOR II FROM 1 TO SIZE(LSTS) DO
    ListANS(II):=REVERSE(LSTS(II));
   END;//FOR  
  END;
  RETURN ListANS;
 END;

 EXPORT SortByABS(LST)
 //Return SORTEDL
 //Note that integers return floats
 BEGIN
  LOCAL TMP:={};
  
  IF SIZE(LST) THEN
   TMP:=SortN({ABS(LST),SIGN(LST)},1);
   RETURN TMP(1)*TMP(2);
  END;
  RETURN {};
 END;

 EXPORT SortByCounts(LST)
 //Returns {LSTV,LSTF} sorted by frequency of occurrence 
 //EG {{1,2,3},{10,30,20}} -> {{2,3,1},{10,20,30}}
 //Return {SORTEDL,SORTEDCOUNTS}
 BEGIN
  ListANS:=ListCOUNTS(LST);//To omit this step, use SortByKey directly
  RETURN SortByKey(ListANS,2);
 END;

 EXPORT SortByKeyLST(LST,KEYLST)
 //Sort LST using KEYLST
 //LST must be sortable. LOL will fail.
 //Return {SORTEDL,SORTEDKEYLST}
 BEGIN
  IF SIZE(LST) AND SIZE(KEYLST) THEN
   RETURN SortN({LST,KEYLST},2);
  END;
  RETURN {};
 END;

 EXPORT SortByKeyNUM(LSTS,Keynum)
 //LSTS is {LSTV,LSTF} as returned by
 //ListCOUNTS(LST);
 //but additional fields are allowed
 //Returns {SORTED,LSTF} sorted by sort key criteria
 //EG {{1,2,3},{10,30,20}} -> {{2,3,1},{10,20,30}}
 //BUG:ONLY SORTS TWO LISTS,
 //BUT CALLING SortN direcLy works
 BEGIN
   IF SIZE(LSTS)≥Keynum THEN
    IF SIZE(LSTS(1))>1 AND SIZE(LSTS(Keynum))>1 THEN
     RETURN SortN(LSTS,Keynum);
    END;
   END;
  RETURN {};
  //To reverse sequence call ReverseLOLS()
 END;
 //These routines are similar
 //Why does one fail TBD
 EXPORT SortByKeyTBD(LSTS,KeyNum)
 //Sort lists by list number KeyNum (with some input guards)
 //Hint: If this gives a data type error call SORTN directly (WHY?) 
 BEGIN
  IF 0<KeyNum≤SIZE(LSTS) AND SIZE(LSTS)>1 THEN
   IF LSTS(1)≠{} AND LSTS(2)≠{} THEN
    RETURN SortN(LSTS,KeyNum);
   END;
  ELSE
   //Potential:not all checked
   //List small, not containing lists, key out of range, key list unsortable
   RAISE(MN+"SortByKey",EL,SortError,KeyNum,ListErrK);
  END;
  RETURN {};
 END;

 EXPORT SortLST(LST) //ex
 //This implementation uses native SORT
 //It is convenient to export when comparing with other sorts
 BEGIN
  IF TYPE(LST)≠TYPELST THEN 
   RAISE(MN+"SortL",EL,SortError,"",ListErrK);
  END;
  RETURN SORT(LST);
 END;

 EXPORT SortN(list,n)
 // From http://www.hpmuseum.org/forum/thread-6179.html?highlight=sort+two+lists
 //Call via ListSORTBYKEY to guard parameters...or call directly with good inputs 
 BEGIN
  LOCAL li,ma;
  ma:=list2mat(list) ;
  li:=SORT(MAKELIST(mat2list(col(ma,I)),I,1,colDim(ma)),n);
  RETURN MAKELIST(mat2list(col(list2mat(li),I)),I,1,rowDim(ma));
 //For example:
 //SORTN({{3,2,1},{15,20,18}},1);// -> {{1,2,3},{18,20,15}}
 //SORTN({{3,2,1},{15,20,18},{32,35,27}},1);// -> {{1,2,3},{18,20,15},{27,35,32}}
 END;

 SortsVERSION() //ex
 BEGIN
  RETURN CRID;
 END;

 
 Pyreverse(LST) //ex
 //Python analogue
 BEGIN
  RETURN REVERSE(LST);
 END;

 EXPORT Pysort(LST,KeyFunc,RReverse)
 //Python analogue SORT
 //PyOpt KeyFunc: STRING EG "ABS" (NULL=NONE)
 //PyOpt PRReverse BOOL
 BEGIN
  LOCAL TMP;
  IF KeyFunc=="" THEN
   ListANS:=SORT(LST);
   RETURN IFTE(RReverse,Pyreverse(ListANS),ListANS);
  END;
  TMP:=EXPR(KeyFunc+"(LST)");
  ListANS:=SortN({LST,TMP},2);
  RETURN IFTE(RReverse,Pyreverse(ListANS(1)),ListANS(1)); 
 END;

 ListPuzzles() //EX
 //SEE http://www.hpmuseum.org/forum/thread-8209.html?highlight=challenge
 BEGIN
  LOCAL VR;
  LOCAL LST:=MAKELIST("",VR,1,5);//40
  LST(2):="31. ListOCCURRENCESWITHSORT";
  CHOOSE(VR,MN+"Puzzles (See thread)",LST);
 END;

EXPORT SortSeeAlso () //ex
 BEGIN
  LOCAL KK;
  LOCAL CatFuns:={
   "REVERSE",
   "reverse",
   "revlist (slower)",
   "SORT",
   "sort"
   };
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,MN+" Relevant Cat Functions",CatFuns)

 END;
 
 EXPORT SortsExamples() //ex
 //In real use, use XXX:=Sort...()
 BEGIN
  LOCAL LL:={1,2,3,4,5,6,7,8,9};
  PRINT();
  PRINT(SortsVERSION);

  PRINT("Is");
  PRINT(IsSortable(0));
  PRINT(IsSortable({})); 
  PRINT(IsSortable(LL));
  PRINT(IsSortablePortable(LL));
  

  PRINT(IsSorted(LL)); 
  PRINT(IsSortedEQ(LL));
 
  PRINT("Reverse");

  PRINT(ReverseLOL({{1,2},{3,4},{5,6}}));
 
  PRINT("Sort");

  //SortByABS
  PRINT(SortByABS({1,2,3,−2})); // -> {1,2,−2,3}
 
  //SortByCounts
  PRINT(SortByCounts({1,2,3,2,3,3})); // -> {{1,2,3},{1,2,3}} 
  //SortByKey
  PRINT(SortByKeyNUM({{1,2,3},{10,30,20}},2)); //-> {{1,3,2},{10,20,30}}
  PRINT(SortByKeyNUM({{1,2,3},{1,22,3}},2));
  PRINT(ReverseLOL(SortByKeyNUM({{1,2,3},{1,22,3}},2)));

  //SortL
  PRINT(SortLST(LL));

  //SortN
  PRINT(SortN({{3,2,1},{15,20,18}},1));// -> {{1,2,3},{18,20,15}}
  PRINT(SortN({{3,2,1},{15,20,18},{32,35,27}},1));// -> {{1,2,3},{18,20,15},{27,35,32}}
  
  PRINT("Py");
  PRINT(Pyreverse({1,2,3}));
  PRINT(Pysort({1,22,3},"",0));
  PRINT(Pysort({1,22,3},"ABS",0));
  PRINT("Exampled");
  //RETURN 0; 
 END;

 EXPORT SORTL()
 BEGIN
  LOCAL LST:={};
  ABOUT();
  //SortExamples();
   
 END;



RE: Sort Lists API: A collection of sort functions - StephenG1CMZ - 12-03-2019 11:42 PM

Version 0.5 implements SortByFun in response to

https://www.hpmuseum.org/forum/thread-6179.html
Code:
 
LOCAL CRID:="SortL API V0.5 © 2019 StephenG1CMZ";
 LOCAL MORETEXT:="A collection of Sort(List) routines brought to you by StephenG1CMZ,\n with some from the forum.";
 LOCAL MN:="SortL.";//Name
 //Also includes REVERSE functions
 //NB REVERSE REVERSES A LIST (WHICH MIGHT HAVE BEEN SORTED)
 //(IT DOES NOT OF ITSELF REVERSE-SORT DESPITE BEING IN THIS SORTL PROGRAM)

 //IMPORT({PPLX}); 
 //IMPORT({List}); //Required
 //Some exportables (ex) omitted to minimise global impact
 //Customise
 EXPORT SortableNumericTypes:={TYPEREAL,TYPEINT};
 LOCAL UNK0:=0;//EMPTY IS UNKNOWN,DEFAULT FALSE
 LOCAL UNK1:=1;//EMPTY IS UNKNOWN,DEFAULT TRUE
 //LOCAL SL:=1;
 //NB To test: sort >1 item
 //End

 //Forward
 IsSortablePortable(LST);
 SortByKey(SORTL,Keynum);
 SortByKeyTBD(SORTL,Keynum);
 SortLST(LST);
 SortN(LST,NN);
 LOCAL NL:="\n";

 //ERR 
 LOCAL ListErrK:=1;
 LOCAL PyErrK:=3;
 LOCAL ERRKIND:={"","Error","","Py Error"};

 EXPORT EL:={
  "(/0) DivideBy0",
  "IndexOutofBoundsException",
  "ListIsEmptyError",
  "ListIsFullError",
  "ListSortError",
  "ListStatisticsError",
  "ItemNotFoundError",
  "ValueError"
 };
 //ERRNO IS ARBITRARY:INDEXES ERRLST
 EXPORT DivBy0Error:=1;
 LOCAL IndexOutOfBoundsException:=2;//List J
 EXPORT ListIsEmptyError:=3;
 LOCAL ListIsFullError:=4;//UNUSED YET
 LOCAL SortError:=5;
 EXPORT ListStatisticsError:=6;
 EXPORT ItemNotFoundError:=7;//List Py
 EXPORT ValueError:=8; // Py
 
 EXPORT ABOUT()
 BEGIN
  MSGBOX(CRID);
  MSGBOX(MORETEXT);
 END;

 TBD()
 BEGIN
  MSGBOX(MN+"TBD");
 END;
 
 IsSortable(LST) //ex
 //For now use Portable
 //Later: as native SORT
 BEGIN
  RETURN IsSortablePortable(LST);
 END;

 EXPORT IsSortableNative(LST)
 //Checks whether the contents of LST are natively sortable
 //Returns 1 TYPESTR only
 //Returns 1 SortableNumeric
 //NB Lists and keys can be sorted but lists alone no
 BEGIN
  LOCAL TP;
  IF SIZE(LST) THEN
   TP:=TYPE(LST(1));
   CASE
    IF TP==TYPESTR THEN 
     RETURN ListIsTYPE(LST,TYPESTR);
    END;
    IF POS(SortableNumericTypes,TP) THEN 
     RETURN ListIsTYPE(LST,SortableNumericTypes);
    END;
    DEFAULT
     RETURN 0;//UNSORTABLE
   END;//CASE
  END;
  RETURN UNK1;//EMPTY INDETERMINATE
 END;

 EXPORT IsSortablePortable(LST)
 //0.Is parameter a list
 //1.Is TYPE of contents OF ORDERABLE DATA
 //2.Is SORTL implemented on that type yet
 //NOTE:
 //IsSORTABLE({Real})=1 AND IsSORTABLE({INT})=1 AND IsSORTABLE({string})=1 but
 //do not assume SORT({mixed}) will deliver your expectations
 //NB The current algorithm reports {1,"4"} as sortable
 //But native sort wont
 //The Portable variant assumes strings and numerics are sortable.
 BEGIN
  LOCAL SortableTypes:=CONCAT(SortableNumericTypes,TYPESTR);
  IF TYPE(LST)==TYPELST THEN
   IF SIZE(LST) THEN
    RETURN ListIsTYPE(LST,SortableTypes);
   END;
   RETURN UNK0;//EMPTY
  END;
  RETURN 0;//NOT LIST:CANNOT BE SORTED
 END;

 IsSortedEQ(LST) //EX
 //Tells whether a list is sorted...inefficiently
 //By sorting it and checking equality
 //(Useful for testing)
 BEGIN
  ListANS:=SortLST(LST);
  RETURN EQ(ListANS,LST);
 END;
 
 EXPORT IsSorted(LST)
 //Looping until 1st descending will/may be quicker TBD
 BEGIN
  RETURN IsSortedEQ(LST);
 END;

 EXPORT ReverseLOL(LSTS)
 //Reverse a list of lists
 //EG {{1,2},{3,4}} -> {{2,1},{4,3}}
 //NONRECURSIVE:2ND LEVEL LISTS ONLY
 //ALL LISTS MUST BE REVERSIBLE
 BEGIN
  LOCAL II;
  ListANS:={};
  IF SIZE(LSTS) THEN
   //REVERSE EACH LST
   FOR II FROM 1 TO SIZE(LSTS) DO
    ListANS(II):=REVERSE(LSTS(II));
   END;//FOR  
  END;
  RETURN ListANS;
 END;

 EXPORT SortByABS(LST)
 //Return LST SORTED BY ABS VALUE
 //Note that #integers return floats
 //ALT: USE SortByFun(LST,ABS(LST))
 //SortByABS is quicker
 BEGIN
  LOCAL TMP:={};
  
  IF SIZE(LST) THEN
   TMP:=SortN({ABS(LST),SIGN(LST)},1);
   RETURN TMP(1)*TMP(2);
  END;
  RETURN {};
 END;

 EXPORT SortByCounts(LST)
 //Returns {LSTV,LSTF} sorted by frequency of occurrence 
 //EG {{1,2,3},{10,30,20}} -> {{2,3,1},{10,20,30}}
 //Return {SORTEDL,SORTEDCOUNTS}
 BEGIN
  ListANS:=ListCOUNTS(LST);//To omit this step, use SortByKey directly
  RETURN SortByKey(ListANS,2);
 END;

 EXPORT SortByFun(LST,SortFun)
 //Sort using SortFun as your sort function 
 //EG SortByFun(LST,ABS(LST)) //BUT SortByABS is faster (Again #integers return floats)
 //EG SortByFun(LST,MYSORTFUN(LST[,ITEM]))
 //Note: The function name alone is not sufficient
 //See https://www.hpmuseum.org/forum/thread-6179.html for alternative CAS syntaxes
 //ALT: Use Pysort("fun")
 BEGIN
  LOCAL SORTORDER;
  LOCAL SORTED:={{},{}};//GUARD EMPTY LIST
  
  IF SIZE(LST) THEN
   SORTORDER:=SortFun;
   SORTED:=Sortn({LST,SORTORDER},2);
  END;
  RETURN SORTED(1); //TO SEE THE SORT ORDER INSTEAD:2
 END;

 EXPORT SortByKeyLST(LST,KEYLST)
 //Sort LST using KEYLST
 //LST must be sortable. LOL will fail.
 //Return {SORTEDL,SORTEDKEYLST}
 BEGIN
  IF SIZE(LST) AND SIZE(KEYLST) THEN
   RETURN SortN({LST,KEYLST},2);
  END;
  RETURN {};
 END;

 EXPORT SortByKeyNUM(LSTS,Keynum)
 //LSTS is {LSTV,LSTF} as returned by
 //ListCOUNTS(LST);
 //but additional fields are allowed
 //Returns {SORTED,LSTF} sorted by sort key criteria
 //EG {{1,2,3},{10,30,20}} -> {{2,3,1},{10,20,30}}
 //BUG:ONLY SORTS TWO LISTS,
 //BUT CALLING SortN direcLy works
 BEGIN
   IF SIZE(LSTS)≥Keynum THEN
    IF SIZE(LSTS(1))>1 AND SIZE(LSTS(Keynum))>1 THEN
     RETURN SortN(LSTS,Keynum);
    END;
   END;
  RETURN {};
  //To reverse sequence call ReverseLOLS()
 END;
 //These routines are similar
 //Why does one fail TBD
 EXPORT SortByKeyTBD(LSTS,KeyNum)
 //Sort lists by list number KeyNum (with some input guards)
 //Hint: If this gives a data type error call SORTN directly (WHY?) 
 BEGIN
  IF 0<KeyNum≤SIZE(LSTS) AND SIZE(LSTS)>1 THEN
   IF LSTS(1)≠{} AND LSTS(2)≠{} THEN
    RETURN SortN(LSTS,KeyNum);
   END;
  ELSE
   //Potential:not all checked
   //List small, not containing lists, key out of range, key list unsortable
   RAISE(MN+"SortByKey",EL,SortError,KeyNum,ListErrK);
  END;
  RETURN {};
 END;

 EXPORT SortLST(LST) //ex
 //This implementation uses native SORT
 //It is convenient to export when comparing with other sorts
 BEGIN
  IF TYPE(LST)≠TYPELST THEN 
   RAISE(MN+"SortL",EL,SortError,"",ListErrK);
  END;
  RETURN SORT(LST);
 END;

 EXPORT SortN(list,n)
 // From http://www.hpmuseum.org/forum/thread-6179.html?highlight=sort+two+lists
 //Call via ListSORTBYKEY to guard parameters...or call directly with good inputs 
 BEGIN
  LOCAL li,ma;
  ma:=list2mat(list) ;
  li:=SORT(MAKELIST(mat2list(col(ma,I)),I,1,colDim(ma)),n);
  RETURN MAKELIST(mat2list(col(list2mat(li),I)),I,1,rowDim(ma));
 //For example:
 //SORTN({{3,2,1},{15,20,18}},1);// -> {{1,2,3},{18,20,15}}
 //SORTN({{3,2,1},{15,20,18},{32,35,27}},1);// -> {{1,2,3},{18,20,15},{27,35,32}}
 END;

 SortsVERSION() //ex
 BEGIN
  RETURN CRID;
 END;

 
 Pyreverse(LST) //ex
 //Python analogue
 BEGIN
  RETURN REVERSE(LST);
 END;

 EXPORT Pysort(LST,KeyFunc,RReverse)
 //Python analogue SORT
 //PyOpt KeyFunc: STRING EG "ABS" (NULL=NONE)
 //PyOpt PRReverse BOOL
 //ALT: Use SortByFun(LST,Fun(LST...))
 //Note: The Py syntax is optional fun without strings
 //Using strings here allows optional null string to be handled
 //The alt SortByFun avoids strings but requires a function
 
 BEGIN
  LOCAL TMP;
  IF KeyFunc=="" THEN
   ListANS:=SORT(LST);
   RETURN IFTE(RReverse,Pyreverse(ListANS),ListANS);
  END;
  TMP:=EXPR(KeyFunc+"(LST)");
  ListANS:=SortN({LST,TMP},2);
  RETURN IFTE(RReverse,Pyreverse(ListANS(1)),ListANS(1)); 
 END;

 ListPuzzles() //EX
 //SEE http://www.hpmuseum.org/forum/thread-8209.html?highlight=challenge
 BEGIN
  LOCAL VR;
  LOCAL LST:=MAKELIST("",VR,1,5);//40
  LST(2):="31. ListOCCURRENCESWITHSORT";
  CHOOSE(VR,MN+"Puzzles (See thread)",LST);
 END;

EXPORT SortSeeAlso () //ex
 BEGIN
  LOCAL KK;
  LOCAL CatFuns:={
   "REVERSE",
   "reverse",
   "revlist (slower)",
   "SORT",
   "sort"
   };
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,MN+" Relevant Cat Functions",CatFuns)

 END;
 
 EXPORT SortsExamples() //ex
 //In real use, use XXX:=Sort...()
 BEGIN
  LOCAL LL:={1,2,3,4,5,6,7,8,9};
  PRINT();
  PRINT(SortsVERSION);

  PRINT("Is");
  PRINT(IsSortable(0));
  PRINT(IsSortable({})); 
  PRINT(IsSortable(LL));
  PRINT(IsSortablePortable(LL));
  

  PRINT(IsSorted(LL)); 
  PRINT(IsSortedEQ(LL));
 
  PRINT("Reverse");

  PRINT(ReverseLOL({{1,2},{3,4},{5,6}}));
 
  PRINT("Sort");

  //SortByABS
  PRINT(SortByABS({1,2,3,−2})); // -> {1,2,−2,3}
 
  //SortByCounts
  PRINT(SortByCounts({1,2,3,2,3,3})); // -> {{1,2,3},{1,2,3}} 
  //SortByKey
  PRINT(SortByKeyNUM({{1,2,3},{10,30,20}},2)); //-> {{1,3,2},{10,20,30}}
  PRINT(SortByKeyNUM({{1,2,3},{1,22,3}},2));
  PRINT(ReverseLOL(SortByKeyNUM({{1,2,3},{1,22,3}},2)));

  //SortL
  PRINT(SortLST(LL));

  //SortN
  PRINT(SortN({{3,2,1},{15,20,18}},1));// -> {{1,2,3},{18,20,15}}
  PRINT(SortN({{3,2,1},{15,20,18},{32,35,27}},1));// -> {{1,2,3},{18,20,15},{27,35,32}}
  
  PRINT("Py");
  PRINT(Pyreverse({1,2,3}));
  PRINT(Pysort({1,22,3},"",0));
  PRINT(Pysort({1,22,3},"ABS",0));
  PRINT("Exampled");
  //RETURN 0; 
 END;

 EXPORT SORTL()
 BEGIN
  LOCAL LST:={};
  ABOUT();
  //SortExamples();
   
 END;



RE: Sort Lists API: A collection of sort functions - StephenG1CMZ - 12-06-2019 12:21 AM

Version 0.6 implements
SortFromItem: Sort by sort distance from an item
and
SortFromItems: Sort by minimum sort distance from a list of items.
The sort distance is a simple ABS(LST-MIN(Items)).


Code:


 LOCAL CRID:="SortL API V0.6 © 2019 StephenG1CMZ";
 LOCAL MORETEXT:="A collection of Sort(List) routines brought to you by StephenG1CMZ,\n with some from the forum.";
 LOCAL MN:="SortL.";//Name
 
 //Dictionary
 //ITEM: an element of a list (or a value which could be in a list)
 //ITEMS: a list of 0..n ITEMs
 //LOL or LSTS: List Of lists EG {{1,2},{3,4}}
 //REVERSE: reverses a list (i.e. to reverse-Sort do REVERSE(SORT()) )
 //All lists may be empty (except: SortN)

 //IMPORT({PPLX}); //TYPE
 //IMPORT({List}); //Required
 //Some exportables (ex) omitted to minimise global impact
 //Customise
 EXPORT SortableNumericTypes:={TYPEREAL,TYPEINT};
 LOCAL UNK0:=0;//EMPTY IS UNKNOWN,DEFAULT FALSE
 LOCAL UNK1:=1;//EMPTY IS UNKNOWN,DEFAULT TRUE
 //LOCAL SL:=1;
 //NB To test: sort >1 item
 //End Custom

 //Forward
 IsSortablePortable(LST);
 SortByKey(SORTL,Keynum);
 SortByKeyTBD(SORTL,Keynum);
 SortLST(LST);
 SortN(LST,NN);

 LOCAL NL:="\n";

 //ERR 
 LOCAL ListErrK:=1;
 LOCAL PyErrK:=3;
 LOCAL ERRKIND:={"","Error","","Py Error"};

 EXPORT EL:={
  "(/0) DivideBy0",
  "IndexOutofBoundsException",
  "ListIsEmptyError",
  "ListIsFullError",
  "ListSortError",
  "ListStatisticsError",
  "ItemNotFoundError",
  "ValueError"
 };
 //ERRNO IS ARBITRARY:INDEXES ERRLST
 EXPORT DivBy0Error:=1;
 LOCAL IndexOutOfBoundsException:=2;//List J
 EXPORT ListIsEmptyError:=3;
 LOCAL ListIsFullError:=4;//UNUSED YET
 LOCAL SortError:=5;
 EXPORT ListStatisticsError:=6;
 EXPORT ItemNotFoundError:=7;//List Py
 EXPORT ValueError:=8; // Py
 
 EXPORT ABOUT()
 BEGIN
  MSGBOX(CRID);
  MSGBOX(MORETEXT);
 END;

 TBD()
 BEGIN
  MSGBOX(MN+"TBD");
 END;
 
 IsSortable(LST) //ex
 //For now use Portable
 //Later: as native SORT
 BEGIN
  RETURN IsSortablePortable(LST);
 END;

 EXPORT IsSortableNative(LST)
 //Checks whether the contents of LST are natively sortable
 //Returns 1 TYPESTR only
 //Returns 1 SortableNumeric
 //NB Lists and keys can be sorted but lists alone no
 BEGIN
  LOCAL TP;
  IF SIZE(LST) THEN
   TP:=TYPE(LST(1));
   CASE
    IF TP==TYPESTR THEN 
     RETURN ListIsTYPE(LST,TYPESTR);
    END;
    IF POS(SortableNumericTypes,TP) THEN 
     RETURN ListIsTYPE(LST,SortableNumericTypes);
    END;
    DEFAULT
     RETURN 0;//UNSORTABLE
   END;//CASE
  END;
  RETURN UNK1;//EMPTY INDETERMINATE
 END;

 EXPORT IsSortablePortable(LST)
 //0.Is parameter a list
 //1.Is TYPE of contents OF ORDERABLE DATA
 //2.Is SORTL implemented on that type yet
 //NOTE:
 //IsSORTABLE({Real})=1 AND IsSORTABLE({INT})=1 AND IsSORTABLE({string})=1 but
 //do not assume SORT({mixed}) will deliver your expectations
 //NB The current algorithm reports {1,"4"} as sortable
 //But native sort wont
 //The Portable variant assumes strings and numerics are sortable.
 BEGIN
  LOCAL SortableTypes:=CONCAT(SortableNumericTypes,TYPESTR);
  IF TYPE(LST)==TYPELST THEN
   IF SIZE(LST) THEN
    RETURN ListIsTYPE(LST,SortableTypes);
   END;
   RETURN UNK0;//EMPTY
  END;
  RETURN 0;//NOT LIST:CANNOT BE SORTED
 END;

 IsSortedEQ(LST) //EX
 //Tells whether a list is sorted...inefficiently
 //By sorting it and checking equality
 //(Useful for testing)
 BEGIN
  ListANS:=SortLST(LST);
  RETURN EQ(ListANS,LST);
 END;
 
 EXPORT IsSorted(LST)
 //Looping until 1st descending will/may be quicker TBD
 BEGIN
  RETURN IsSortedEQ(LST);
 END;

 EXPORT ReverseLOL(LSTS)
 //Reverse a list of lists
 //EG {{1,2},{3,4}} -> {{2,1},{4,3}}
 //NONRECURSIVE:2ND LEVEL LISTS ONLY
 //ALL LISTS MUST BE REVERSIBLE
 BEGIN
  LOCAL II;
  ListANS:={};
  IF SIZE(LSTS) THEN
   //REVERSE EACH LST
   FOR II FROM 1 TO SIZE(LSTS) DO
    ListANS(II):=REVERSE(LSTS(II));
   END;//FOR  
  END;
  RETURN ListANS;
 END;

 EXPORT SortByABS(LST)
 //Return LST SORTED BY ABS VALUE
 //Note that #integers return floats
 //ALT: USE SortByFun(LST,ABS(LST))
 //SortByABS is quicker
 BEGIN
  LOCAL TMP:={};
  
  IF SIZE(LST) THEN
   TMP:=SortN({ABS(LST),SIGN(LST)},1);
   RETURN TMP(1)*TMP(2);
  END;
  RETURN {};
 END;

 EXPORT SortByCounts(LST)
 //Returns {LSTV,LSTF} sorted by frequency of occurrence 
 //EG {{1,2,3},{10,30,20}} -> {{2,3,1},{10,20,30}}
 //Return {SORTEDL,SORTEDCOUNTS}
 BEGIN
  ListANS:=ListCOUNTS(LST);//To omit this step, use SortByKey directly
  RETURN SortByKey(ListANS,2);
 END;

 EXPORT SortByFun(LST,SortFun)
 //Sort using SortFun as your sort function 
 //EG SortByFun(LST,ABS(LST)) //BUT SortByABS is faster (Again #integers return floats)
 //EG SortByFun(LST,MYSORTFUN(LST[,ITEM]))
 //Note: The function name alone is not sufficient
 //See https://www.hpmuseum.org/forum/thread-6179.html for alternative CAS syntaxes
 //ALT: Use Pysort("fun")
 BEGIN
  LOCAL SORTORDER;
  LOCAL SORTED:={{},{}};//GUARD EMPTY LIST
  
  IF SIZE(LST) THEN
   SORTORDER:=SortFun;
   SORTED:=Sortn({LST,SORTORDER},2); 
  END;
  RETURN SORTED(1); //TO SEE THE SORT ORDER INSTEAD:2
 END;

 EXPORT SortByKeyLST(LST,KEYLST)
 //Sort LST using KEYLST
 //LST must be sortable. LOL will fail.
 //Return {SORTEDL,SORTEDKEYLST}
 BEGIN
  IF SIZE(LST) AND SIZE(KEYLST) THEN
   RETURN SortN({LST,KEYLST},2);
  END;
  RETURN {};
 END;

 EXPORT SortByKeyNUM(LSTS,Keynum)
 //LSTS is {LSTV,LSTF} as returned by
 //ListCOUNTS(LST);
 //but additional fields are allowed
 //Returns {SORTED,LSTF} sorted by sort key criteria
 //EG {{1,2,3},{10,30,20}} -> {{2,3,1},{10,20,30}}
 //BUG:ONLY SORTS TWO LISTS,
 //BUT CALLING SortN direcLy works
 BEGIN
   IF SIZE(LSTS)≥Keynum THEN
    IF SIZE(LSTS(1))>1 AND SIZE(LSTS(Keynum))>1 THEN
     RETURN SortN(LSTS,Keynum);
    END;
   END;
  RETURN {};
  //To reverse sequence call ReverseLOLS()
 END;
 //These routines are similar
 //Why does one fail TBD
 EXPORT SortByKeyTBD(LSTS,KeyNum)
 //Sort lists by list number KeyNum (with some input guards)
 //Hint: If this gives a data type error call SORTN directly (WHY?) 
 BEGIN
  IF 0<KeyNum≤SIZE(LSTS) AND SIZE(LSTS)>1 THEN
   IF LSTS(1)≠{} AND LSTS(2)≠{} THEN
    RETURN SortN(LSTS,KeyNum);
   END;
  ELSE
   //Potential:not all checked
   //List small, not containing lists, key out of range, key list unsortable
   RAISE(MN+"SortByKey",EL,SortError,KeyNum,ListErrK);
  END;
  RETURN {};
 END;

 EXPORT SortFromItem(LST,ITEM)
  //Return simple sort distance
  //Return LST SORTED BY NUMERICAL ABS VALUE FROM ITEM
  //Note that #integers return floats
  //=SortFromItems(LST,{ITEM})
  //ALT: USE SortByFun(LST,MYSORTFUN(LST...))
 BEGIN
  LOCAL TMP:={}; 
  IF SIZE(LST) THEN  
   TMP:=SortByFun(LST,ABS(LST-ITEM));  
  END;
  RETURN TMP;
 END;

 EXPORT SortFromItems(LST,ITEMS)
 //Sort by min sort distance from a list of items
 //#integers return floats
 //EMPTY LISTS: RETURN EMPTY LIST
 // (or: perhaps empty ITEMS should simply SORT(LST)?) 
 BEGIN
  LOCAL DX:={};
  LOCAL TMP:={{},{}}; 
  LOCAL II;
  IF SIZE(LST) AND SIZE(ITEMS) THEN 
   //IF SIZE(ITEMS)==1 THEN //OPTIONAL OPTIMISE
   // RETURN SortFromItem(LST,ITEMS(1));
   //END;
   //DX:=sort distance from nearest ITEM
   DX:=MAKELIST(MIN(ABS(LST(II)-ITEMS)),II,1,SIZE(LST));
   TMP:=SortN({LST,DX},2);  
  END;
  //PRINT(TMP);
  RETURN TMP(1);
 END;

 EXPORT SortLST(LST) //ex
 //This implementation uses native SORT
 //It is convenient to export when comparing with other sorts
 BEGIN
  IF TYPE(LST)≠TYPELST THEN 
   RAISE(MN+"SortL",EL,SortError,"",ListErrK);
  END;
  RETURN SORT(LST);
 END;

 EXPORT SortN(list,n)
 // From http://www.hpmuseum.org/forum/thread-6179.html?highlight=sort+two+lists
 //Call via ListSORTBYKEY to guard parameters...or call directly with good inputs 
 BEGIN
  LOCAL li,ma;
  ma:=list2mat(list) ;
  li:=SORT(MAKELIST(mat2list(col(ma,I)),I,1,colDim(ma)),n);
  RETURN MAKELIST(mat2list(col(list2mat(li),I)),I,1,rowDim(ma));
 //For example:
 //SORTN({{3,2,1},{15,20,18}},1);// -> {{1,2,3},{18,20,15}}
 //SORTN({{3,2,1},{15,20,18},{32,35,27}},1);// -> {{1,2,3},{18,20,15},{27,35,32}}
 END;

 SortsVERSION() //ex
 BEGIN
  RETURN CRID;
 END;

 
 Pyreverse(LST) //ex
 //Python analogue
 BEGIN
  RETURN REVERSE(LST);
 END;

 EXPORT Pysort(LST,KeyFunc,RReverse)
 //Python analogue SORT
 //PyOpt KeyFunc: STRING EG "ABS" (NULL=NONE)
 //PyOpt PRReverse BOOL
 //ALT: Use SortByFun(LST,Fun(LST...))
 //Note: The Py syntax is optional fun without strings
 //Using strings here allows optional null string to be handled
 //The alt SortByFun avoids strings but requires a function
 
 BEGIN
  LOCAL TMP;
  IF KeyFunc=="" THEN
   ListANS:=SORT(LST);
   RETURN IFTE(RReverse,Pyreverse(ListANS),ListANS);
  END;
  TMP:=EXPR(KeyFunc+"(LST)");
  ListANS:=SortN({LST,TMP},2);
  RETURN IFTE(RReverse,Pyreverse(ListANS(1)),ListANS(1)); 
 END;

 ListPuzzles() //EX
 //SEE http://www.hpmuseum.org/forum/thread-8209.html?highlight=challenge
 BEGIN
  LOCAL VR;
  LOCAL LST:=MAKELIST("",VR,1,5);//40
  LST(2):="31. ListOCCURRENCESWITHSORT";
  CHOOSE(VR,MN+"Puzzles (See thread)",LST);
 END;

EXPORT SortSeeAlso () //ex
 BEGIN
  LOCAL KK;
  LOCAL CatFuns:={
   "REVERSE",
   "reverse",
   "revlist (slower)",
   "SORT",
   "sort"
   };
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,MN+" Relevant Cat Functions",CatFuns)

 END;
 
 EXAMPLESORTFROM()
 //EG DISTANCE FROM FIRST AID POSTS AT 5 mile intervals along a half marathon
 BEGIN
  LOCAL ITEMS:={0,5,10};//FIRST AID POSTS
  //LOCAL LST:={10,5,−20,−5,20,−10};
  LOCAL LST:={1,2,3,4,5,6,7,8,9,10,11,12,13};
  LOCAL OUTLST;
  PRINT();
  PRINT(OUTLST:=SortFromItems(LST,ITEMS));//CLOSEST LISTED FIRST
 END;

 EXPORT SortsExamples() //ex
 //In real use, use XXX:=Sort...()
 BEGIN
  LOCAL LL:={1,2,3,4,5,6,7,8,9};
  PRINT();
  PRINT(SortsVERSION);

  PRINT("Is");
  PRINT(IsSortable(0));
  PRINT(IsSortable({})); 
  PRINT(IsSortable(LL));
  PRINT(IsSortablePortable(LL));
  

  PRINT(IsSorted(LL)); 
  PRINT(IsSortedEQ(LL));
 
  PRINT("Reverse");

  PRINT(ReverseLOL({{1,2},{3,4},{5,6}}));
 
  PRINT("Sort");

  //SortByABS
  PRINT(SortByABS({1,2,3,−2})); // -> {1,2,−2,3}
 
  //SortByCounts
  PRINT(SortByCounts({1,2,3,2,3,3})); // -> {{1,2,3},{1,2,3}} 
  //SortByKey
  PRINT(SortByKeyNUM({{1,2,3},{10,30,20}},2)); //-> {{1,3,2},{10,20,30}}
  PRINT(SortByKeyNUM({{1,2,3},{1,22,3}},2));
  PRINT(ReverseLOL(SortByKeyNUM({{1,2,3},{1,22,3}},2)));

  //SortL
  PRINT(SortLST(LL));

  //SortN
  PRINT(SortN({{3,2,1},{15,20,18}},1));// -> {{1,2,3},{18,20,15}}
  PRINT(SortN({{3,2,1},{15,20,18},{32,35,27}},1));// -> {{1,2,3},{18,20,15},{27,35,32}}
  
  PRINT("Py");
  PRINT(Pyreverse({1,2,3}));
  PRINT(Pysort({1,22,3},"",0));
  PRINT(Pysort({1,22,3},"ABS",0));
  PRINT("Exampled");
  //RETURN 0; 
 END;

 EXPORT SORTL()
 BEGIN
  LOCAL LST:={};
  ABOUT();
  //SortExamples();
   
 END;



RE: Sort Lists API: A collection of sort functions - StephenG1CMZ - 12-11-2019 07:24 PM

Version 0.7

SortByKey functions rewritten
SortByIndex implemented

Code:



 LOCAL CRID:="SortL API V0.7 © 2019 StephenG1CMZ";
 LOCAL MORETEXT:="A collection of Sort(List) routines brought to you by StephenG1CMZ,\n with some from the forum.";
 LOCAL MN:="SortL.";//Name
 
 //Dictionary
 //ITEM: an element of a list (or a value which could be in a list)
 //ITEMS: a list of 0..n ITEMs
 //KEYLST: sorting this sorts your other list(s)
 //LST: a list 
 //LOL or LSTS: List Of lists EG {{1,2},{3,4}} (just {{1,2}} may be OK)
 //REVERSE: reverses a list (i.e. to reverse-Sort do REVERSE(SORT()) )
 //All lists may be empty (except: SortN)

 //IMPORT({PPLX}); //TYPE
 //IMPORT({List}); //Required
 //Some exportables (ex) omitted to minimise global impact
 //Customise
 EXPORT SortableNumericTypes:={TYPEREAL,TYPEINT};
 LOCAL UNK0:=0;//EMPTY IS UNKNOWN,DEFAULT FALSE
 LOCAL UNK1:=1;//EMPTY IS UNKNOWN,DEFAULT TRUE
 //LOCAL SL:=1;
 //NB To test: sort >1 item
 //End Custom

 //Forward
 IsSortablePortable(LST);
 SortByKey(SORTL,Keynum);
 SortLST(LST);
 SortN(LST,NN);

 LOCAL NL:="\n";

 //ERR 
 LOCAL ListErrK:=1;
 LOCAL PyErrK:=3;
 LOCAL ERRKIND:={"","Error","","Py Error"};

 EXPORT EL:={
  "(/0) DivideBy0",
  "IndexOutofBoundsException",
  "ListIsEmptyError",
  "ListIsFullError",
  "ListSortError",
  "ListStatisticsError",
  "ItemNotFoundError",
  "ValueError"
 };
 //ERRNO IS ARBITRARY:INDEXES ERRLST
 EXPORT DivBy0Error:=1;
 LOCAL IndexOutOfBoundsException:=2;//List J
 EXPORT ListIsEmptyError:=3;
 LOCAL ListIsFullError:=4;//UNUSED YET
 LOCAL SortError:=5;
 EXPORT ListStatisticsError:=6;
 EXPORT ItemNotFoundError:=7;//List Py
 EXPORT ValueError:=8; // Py
 
 EXPORT ABOUT()
 BEGIN
  MSGBOX(CRID);
  MSGBOX(MORETEXT);
 END;

 TBD()
 BEGIN
  MSGBOX(MN+"TBD");
 END;
 
 IsSortable(LST) //ex
 //For now use Portable
 //Later: as native SORT
 BEGIN
  RETURN IsSortablePortable(LST);
 END;

 EXPORT IsSortableNative(LST)
 //Checks whether the contents of LST are natively sortable
 //Returns 1 TYPESTR only
 //Returns 1 SortableNumeric
 //NB Lists and keys can be sorted but lists alone no
 BEGIN
  LOCAL TP;
  IF SIZE(LST) THEN
   TP:=TYPE(LST(1));
   CASE
    IF TP==TYPESTR THEN 
     RETURN ListIsTYPE(LST,TYPESTR);
    END;
    IF POS(SortableNumericTypes,TP) THEN 
     RETURN ListIsTYPE(LST,SortableNumericTypes);
    END;
    DEFAULT
     RETURN 0;//UNSORTABLE
   END;//CASE
  END;
  RETURN UNK1;//EMPTY INDETERMINATE
 END;

 EXPORT IsSortablePortable(LST)
 //0.Is parameter a list
 //1.Is TYPE of contents OF ORDERABLE DATA
 //2.Is SORTL implemented on that type yet
 //NOTE:
 //IsSORTABLE({Real})=1 AND IsSORTABLE({INT})=1 AND IsSORTABLE({string})=1 but
 //do not assume SORT({mixed}) will deliver your expectations
 //NB The current algorithm reports {1,"4"} as sortable
 //But native sort wont
 //The Portable variant assumes strings and numerics are sortable.
 BEGIN
  LOCAL SortableTypes:=CONCAT(SortableNumericTypes,TYPESTR);
  IF TYPE(LST)==TYPELST THEN
   IF SIZE(LST) THEN
    RETURN ListIsTYPE(LST,SortableTypes);
   END;
   RETURN UNK0;//EMPTY
  END;
  RETURN 0;//NOT LIST:CANNOT BE SORTED
 END;

 IsSortedEQ(LST) //EX
 //Tells whether a list is sorted...inefficiently
 //By sorting it and checking equality
 //(Useful for testing)
 BEGIN
  ListANS:=SortLST(LST);
  RETURN EQ(ListANS,LST);
 END;
 
 EXPORT IsSorted(LST)
 //Looping until 1st descending will/may be quicker TBD
 BEGIN
  RETURN IsSortedEQ(LST);
 END;

 EXPORT ReverseLOL(LSTS)
 //Reverse a list of lists
 //EG {{1,2},{3,4}} -> {{2,1},{4,3}}
 //NONRECURSIVE:2ND LEVEL LISTS ONLY
 //ALL LISTS MUST BE REVERSIBLE
 BEGIN
  LOCAL II;
  ListANS:={};
  IF SIZE(LSTS) THEN
   //REVERSE EACH LST
   FOR II FROM 1 TO SIZE(LSTS) DO
    ListANS(II):=REVERSE(LSTS(II));
   END;//FOR  
  END;
  RETURN ListANS;
 END;

 EXPORT SortByABS(LST)
 //Return LST SORTED BY ABS VALUE
 //Note that #integers return floats
 //ALT: USE SortByFun(LST,ABS(LST))
 //SortByABS is quicker
 BEGIN
  LOCAL TMP:={};
  
  IF SIZE(LST) THEN
   TMP:=SortN({ABS(LST),SIGN(LST)},1);
   RETURN TMP(1)*TMP(2);
  END;
  RETURN {};
 END;

 EXPORT SortByCounts(LST)
 //Returns {LSTV,LSTF} sorted by frequency of occurrence 
 //EG {{1,2,3},{10,30,20}} -> {{2,3,1},{10,20,30}}
 //Return {SORTEDL,SORTEDCOUNTS}
 BEGIN
  ListANS:=ListCOUNTS(LST);//To omit this step, use SortByKey directly
  RETURN SortByKey(ListANS,2);
 END;

 EXPORT SortByFun(LST,SortFun)
 //Sort using SortFun as your sort function 
 //EG SortByFun(LST,ABS(LST)) //BUT SortByABS is faster (Again #integers return floats)
 //EG SortByFun(LST,MYSORTFUN(LST[,ITEM]))
 //Note: The function name alone is not sufficient
 //See https://www.hpmuseum.org/forum/thread-6179.html for alternative CAS syntaxes
 //ALT: Use Pysort("fun")
 BEGIN
  LOCAL SORTORDER;
  LOCAL SORTED:={{},{}};//GUARD EMPTY LIST
  
  IF SIZE(LST) THEN
   SORTORDER:=SortFun;
   SORTED:=SortN({LST,SORTORDER},2); 
  END;
  RETURN SORTED(1); //TO SEE THE SORT ORDER INSTEAD:2
 END;

 EXPORT SortByIndex(LST,XLST)
 //Return the indexes from LST specified by XLST
 //A partial list is valid, as are repetitions
 //An entry in XLST > SIZE(LST) could be checked 1st
 BEGIN
  LOCAL II;
  LOCAL TMP:={0};
  IF SIZE(LST) AND SIZE(XLST) THEN
  
   //To improve speed omit test
   //Hint: Check this 1st before calling this routine multiple times
   // when you have several similar lists
   //TMP:=MAKELIST((XLST(II)>SIZE(LST)),II,1,SIZE(XLST));//OPTIONAL TEST  
 
   //IF ΣLIST(TMP)THEN 
   // RAISE(MN+"SortByIndex",EL,SortError,ΣLIST(TMP),ListErrK); 
   //ELSE
    RETURN MAKELIST(LST(XLST(II)),II,1,SIZE(XLST));
   //END;
  END;
  RETURN {};
 END;

 EXPORT SortByKeyLST(LST,KEYLST)
 //Sort 1 LST using KEYLST. 
 //KEYLST will be sorted to determine how to sort LST
 //LST must be sortable. LOL will fail.
 //Cf: SortByKey({LST},KEYLST) 
 BEGIN
  LOCAL TMP;
  IF SIZE(LST) AND SIZE(KEYLST) THEN
   TMP:=SortN({LST,KEYLST},2);
   //Make Customisable?
   //One will match SortByKey({LST},KEYLST)
   RETURN TMP;    // {SORTEDLST,SORTEDKEYLST}
   RETURN TMP(1); // SORTEDLST 
  END;
  RETURN {};
 END;

 SortByKeyLSTS(LSTS,KEYLST)
 //Sort LSTS using KEYLST to order. 
 //KEYLST will be sorted to determine how to sort LST
 //Return: SORTEDLSTS
 //If KEYLST exists within LSTS use: SortByKeyNUM(LSTS,N)
 BEGIN
  LOCAL TMP;
  IF SIZE(LSTS) AND SIZE(KEYLST) THEN
   LSTS(0):=KEYLST;
   TMP:= SortN(LSTS,SIZE(LSTS));
   RETURN ListBEFORE(TMP,SIZE(TMP));
  END;
  RETURN {};
 END;

 SortByKeyNUM(LSTS,Keynum)
 //LSTS is {LSTV,LSTF} as returned by
 //ListCOUNTS(LST);
 //but additional fields are allowed
 //Returns {SORTED LSTS} sorted by sort key criteria
 //EG ({{1,2,3},{10,30,20}},2) -> {{2,3,1},{10,20,30}}
 BEGIN
   IF 0<Keynum≤SIZE(LSTS) THEN
    IF SIZE(LSTS(1)) AND SIZE(LSTS(Keynum)) THEN 
     //Strictly all are lists of same size
     RETURN SortN(LSTS,Keynum);
    END;
   END; 
   //Potential errors:not all checked
   //List small, not containing lists, key out of range, key list unsortable 
   RAISE(MN+"SortByKey",EL,SortError,Keynum,ListErrK); 
   RETURN {};
  //To reverse sequence call ReverseLOLS()
 END;

 EXPORT SortByKey(LSTS,KEY)
 //Sort LSTS by KEY
 //EG (LSTS,2) OR (LSTS,{6,5}) WHERE LSTS={{1,2},{3,4}}
 BEGIN
  CASE
   IF TYPE(KEY)==TYPELST THEN SortByKeyLSTS(LSTS,KEY) END;
   DEFAULT //numeric KEY param
    SortByKeyNUM(LSTS,KEY);
  END;
 END;

 EXPORT SortFromItem(LST,ITEM)
  //Return simple sort distance
  //Return LST SORTED BY NUMERICAL ABS VALUE FROM ITEM
  //Note that #integers return floats
  //=SortFromItems(LST,{ITEM})
  //ALT: USE SortByFun(LST,MYSORTFUN(LST...))
 BEGIN
  LOCAL TMP:={}; 
  IF SIZE(LST) THEN  
   TMP:=SortByFun(LST,ABS(LST-ITEM));  
  END;
  RETURN TMP;
 END;

 EXPORT SortFromItems(LST,ITEMS)
 //Sort by min sort distance from a list of items
 //#integers return floats
 //EMPTY LISTS: RETURN EMPTY LIST
 // (or: perhaps empty ITEMS should simply SORT(LST)?) 
 BEGIN
  LOCAL DX:={};
  LOCAL TMP:={{},{}}; 
  LOCAL II;
  IF SIZE(LST) AND SIZE(ITEMS) THEN 
   //IF SIZE(ITEMS)==1 THEN //OPTIONAL OPTIMISE
   // RETURN SortFromItem(LST,ITEMS(1));
   //END;
   //DX:=sort distance from nearest ITEM
   DX:=MAKELIST(MIN(ABS(LST(II)-ITEMS)),II,1,SIZE(LST));
   TMP:=SortN({LST,DX},2);  
  END;
  RETURN TMP(1);
 END;

 SortLST(LST) //ex
 //This implementation uses native SORT
 //It is convenient to export when comparing with other sorts
 BEGIN
  IF TYPE(LST)≠TYPELST THEN 
   RAISE(MN+"SortLST",EL,SortError,"",ListErrK);
   RETURN {};
  END;
  RETURN SORT(LST);
 END;

 EXPORT SortN(list,n)
 // From http://www.hpmuseum.org/forum/thread-6179.html?highlight=sort+two+lists
 //Call via ListSORTBYKEY to guard parameters...or call directly with good inputs 
 BEGIN
  LOCAL li,ma;
  ma:=list2mat(list) ;
  li:=SORT(MAKELIST(mat2list(col(ma,I)),I,1,colDim(ma)),n);
  RETURN MAKELIST(mat2list(col(list2mat(li),I)),I,1,rowDim(ma));
 //For example:
 //SORTN({{3,2,1},{15,20,18}},1);// -> {{1,2,3},{18,20,15}}
 //SORTN({{3,2,1},{15,20,18},{32,35,27}},1);// -> {{1,2,3},{18,20,15},{27,35,32}}
 END;

 SortsVERSION() //ex
 BEGIN
  RETURN CRID;
 END;

 Pyreverse(LST) //ex
 //Python analogue
 BEGIN
  RETURN REVERSE(LST);
 END;

 EXPORT Pysort(LST,KeyFunc,RReverse)
 //Python analogue SORT
 //PyOpt KeyFunc: STRING EG "ABS" (NULL=NONE)
 //PyOpt PRReverse BOOL
 //ALT: Use SortByFun(LST,Fun(LST...))
 //Note: The Py syntax is optional fun without strings
 //Using strings here allows optional null string to be handled
 //The alt SortByFun avoids strings but requires a function
 
 BEGIN
  LOCAL TMP;
  IF KeyFunc=="" THEN
   ListANS:=SORT(LST);
   RETURN IFTE(RReverse,Pyreverse(ListANS),ListANS);
  END;
  TMP:=EXPR(KeyFunc+"(LST)");
  ListANS:=SortN({LST,TMP},2);
  RETURN IFTE(RReverse,Pyreverse(ListANS(1)),ListANS(1)); 
 END;

 ListPuzzles() //EX
 //SEE http://www.hpmuseum.org/forum/thread-8209.html?highlight=challenge
 BEGIN
  LOCAL VR;
  LOCAL LST:=MAKELIST("",VR,1,5);//40
  LST(2):="31. ListOCCURRENCESWITHSORT";
  CHOOSE(VR,MN+"Puzzles (See thread)",LST);
 END;

EXPORT SortSeeAlso () //ex
 BEGIN
  LOCAL KK;
  LOCAL CatFuns:={
   "REVERSE",
   "reverse",
   "revlist (slower)",
   "SORT",
   "sort"
   };
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,MN+" Relevant Cat Functions",CatFuns)

 END;
 
 EXAMPLESORTFROM()
 //EG DISTANCE FROM FIRST AID POSTS AT 5 mile intervals along a half marathon
 BEGIN
  LOCAL ITEMS:={0,5,10};//FIRST AID POSTS
  //LOCAL LST:={10,5,−20,−5,20,−10};
  LOCAL LST:={1,2,3,4,5,6,7,8,9,10,11,12,13};
  LOCAL OUTLST;
  PRINT();
  PRINT(OUTLST:=SortFromItems(LST,ITEMS));//CLOSEST LISTED FIRST
 END;

 EXPORT SortsExamples() //ex
 //In real use, use XXX:=Sort...()
 BEGIN
  LOCAL LL:={1,2,3,4,5,6,7,8,9};
  PRINT();
  PRINT(SortsVERSION);

  PRINT("Is");
  PRINT(IsSortable(0));
  PRINT(IsSortable({})); 
  PRINT(IsSortable(LL));
  PRINT(IsSortablePortable(LL));
  

  PRINT(IsSorted(LL)); 
  PRINT(IsSortedEQ(LL));
 
  PRINT("Reverse");

  PRINT(ReverseLOL({{1,2},{3,4},{5,6}}));
 
  PRINT("Sort");

  //SortByABS
  PRINT(SortByABS({1,2,3,−2})); // -> {1,2,−2,3}
 
  //SortByCounts
  PRINT(SortByCounts({1,2,3,2,3,3})); // -> {{1,2,3},{1,2,3}} 
  //SortByKey
  PRINT(SortByKeyNUM({{1,2,3},{10,30,20}},2)); //-> {{1,3,2},{10,20,30}}
  PRINT(SortByKeyNUM({{1,2,3},{1,22,3}},2));
  PRINT(ReverseLOL(SortByKeyNUM({{1,2,3},{1,22,3}},2)));

  //SortL
  PRINT(SortLST(LL));

  //SortN
  PRINT(SortN({{3,2,1},{15,20,18}},1));// -> {{1,2,3},{18,20,15}}
  PRINT(SortN({{3,2,1},{15,20,18},{32,35,27}},1));// -> {{1,2,3},{18,20,15},{27,35,32}}
  
  PRINT("Py");
  PRINT(Pyreverse({1,2,3}));
  PRINT(Pysort({1,22,3},"",0));
  PRINT(Pysort({1,22,3},"ABS",0));
  PRINT("Exampled");
  //RETURN 0; 
 END;

 EXPORT SORTL()
 BEGIN
  LOCAL LST:={};
  ABOUT();
  //SortExamples();
   
 END;



RE: Sort Lists API: A collection of sort functions - StephenG1CMZ - 04-27-2021 08:08 PM

I have discovered that some of these are not working... Either failing at run-time, or older versions failing to compile.
Where I have had this happen before with code that used to work for me, it has sometimes been caused by a dependence in the published version on some functions present in a backup copy (which the Prime implicitly calls if the version in the latest version is renamed or out of scope), after that backup is deleted.


RE: Sort Lists API: A collection of sort functions - StephenG1CMZ - 05-18-2021 03:12 PM

One of the errors I am seeing is an index out of bounds error... Perhaps an index-from-0 error?