Post Reply 
List API (G1CMZ): List Processing API
10-31-2017, 11:21 PM (This post was last modified: 11-01-2017 09:18 AM by StephenG1CMZ.)
Post: #1
List API (G1CMZ): List Processing API
I have implemented a collection of list processing routines.

The aim was to provide many of the list primitives listed on Wikipedia, so as to enable common names to be used across platforms. As such, some routines are hardly useful - I would expect most will continue to use LL(0):=ITEM rather than call APPEND. But having the names available can aid portability - though in the case of Python names, they serve more to remind me of what built-in functions are available, rather than in any expectation of compatibility with a language that indexes lists from 0.

I have also written some useful procedures I have not seen elsewhere.

Stephen Lewkowicz (G1CMZ)
Visit this user's website Find all posts by this user
Quote this message in a reply
10-31-2017, 11:23 PM (This post was last modified: 11-05-2017 09:54 PM by StephenG1CMZ.)
Post: #2
RE: List API (G1CMZ): List Processing API
Version 0.02

Although there is some error detection, many routines are not robust.

Code:

 
 LOCAL CRID:="List API V0.02 © 2017 StephenG1CMZ";

 //Customise
 EXPORT ListErrShow:=1;//SHOW ERRORS
 //End

 //Forward
 ListSORT(LST);
 ListREMOVEDUPLICATES(LST);
 ListREMOVEX(LST,POSN);

 //NB In main routines (ie not Python)
 //POSN parameter is >=0 (0=LAST)
 //POSN returned is ≥0 (PPL,0=NOTIN)

 //LOCAL SL:=1;
 LOCAL NL:="\n";

 EXPORT ListTYPE:=6;//MAGIC NUMBER FOR LISTS.Exported to avoid magic

 LOCAL ListANS;//OUTPUT LIST(WHEN NOT RETURNED)
  //Also, useful temporary results 

 //ERR 
 LOCAL ListLastError:=0;
 LOCAL ERRLST:={
  "IndexOutofBoundsException",
  "ListIsEmptyError",
  "ListStatisticsError",
  "Py: ItemNotFoundError",
  "Py: ValueError"
 };
 //ERRNO IS ARBITRARY:INDEXES ERRLST
 LOCAL IndexOutOfBoundsException:=1;
 LOCAL ListIsEmptyError:=2;
 LOCAL ListStatisticsError:=3;//
 LOCAL ItemNotFoundError:=4;
 LOCAL ValueError:=5; 
 
 EXPORT ABOUT()
 BEGIN
  MSGBOX(CRID);
 END;

 TBD()
 BEGIN
  MSGBOX( "List: TBD");
 END;

 EXPORT RAISE(ERR,CULPRIT,SEVERITY)
 //Only exported for testing
 BEGIN
  IF ListErrShow AND SEVERITY THEN
   MSGBOX("List: "+ERRLST(ERR)+NL+CULPRIT);
  END;
  ListLastError:=ERR;
 END;

 //MAINLY STANDARD FUNCTIONS

 EXPORT ListAFTER(LST,POSN)
 //Slice After POSN:POSN>0
 BEGIN
  LOCAL FRM:=POSN+1;
  RETURN IFTE(FRM>SIZE(LST),{},LST({FRM,SIZE(LST)}));
 END;

 EXPORT ListANDBOOL(LST,LSTBOOL,NewValue)
 //Replace items ANDed out with NULL(NewValue)
 //EG ({"AA","BB"},{0,1},"CHAR(0)") = {"","BB"}//Note the quotes
 //EG ({11,13},{0,1},"12")//NOMORETHAN12
 //RequirementSpec:
 //http://www.hpmuseum.org/forum/thread-5092.html
 //Usage:
 //http://www.hpmuseum.org/forum/thread-5031.html
 //See also:MaskBOOL
 BEGIN
  //Guard against empty "" giving syn err
  LOCAL MYNULL:=IFTE(NewValue=="","CHAR(0)",NewValue);

  RETURN EXECON("IFTE(&2,&1,"+MYNULL+")",LST,LSTBOOL);
 END;

 EXPORT ListAPPEND(LST,ITEM)
 //APPEND ITEM TO LIST
 //EG L2:=APPEND(L2,3)
 //PPL:L2(0):=3;
 //Py:APPEND(L2,3)
 BEGIN
  RETURN LST(0):=ITEM; 
 END;

 EXPORT ListBEFORE(LST,POSN)
 //Slice Before POSN: 
 BEGIN
  LOCAL TOO:=POSN-1;
  IF POSN==0 THEN
    RETURN ListBEFORE(LST,SIZE(POSN));
  END;
  RETURN IFTE(TOO>0,LST({1,TOO}),{});
 END;

 EXPORT ListCONCAT(LST1,LST2)
 //CONCATENATE
 BEGIN
  CONCAT(LST1,LST2);
 END;

 EXPORT ListCOUNT(LST,ITEM)
 //Count Instances of ITEM in LST
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  CASE
   IF POSN==0 THEN RETURN 0; END;
   //IF POSN==SIZE(LST)  THEN RETURN 1; END;
   DEFAULT
    //FOR LISTS WIH MANY DUPLICATES:
    //AN ITERATIVE SOLN WILL BE NEEDED
    RETURN 1+ListCOUNT(ListAFTER(LST,POSN),ITEM);
  END; 
 END;

 EXPORT ListCOUNTANYDUPLICATES_SORTED(SortedLST)
 //Count how many duplicates in a sortedlist,Return a REAL INT
 //({1,9,9}=1 dup, {1,2,2,3,3,3}=3 dup)
 BEGIN
  LOCAL II;
  LOCAL DUPCOUNT:=0;
  IF SIZE(SortedLST)>1 THEN
   FOR II FROM 1 TO SIZE(SortedLST)-1 DO
    IF SortedLST(II) ==SortedLST(II+1) THEN
     DUPCOUNT:=DUPCOUNT+1;
    END;//IF
   END;//FOR
   //ELSE:SMALL LISTS HAVE NO DUPLICATES
  END;//IF
  RETURN DUPCOUNT;
 END;

 EXPORT ListCOUNTANYDUPLICATES(LST)
 //Current Implementation yields a sorted LST
 //But might change
 BEGIN
  ListANS:=ListSORT(LST);
  RETURN ListCOUNTANYDUPLICATES_SORTED(ListANS);
 END;
 
 EXPORT ListFIND(LST,ITEM)
 //Find all instances of ITEM
 BEGIN
  LOCAL II;
  LOCAL LSTPOSNS:={};

  IF SIZE(LST) THEN //
   //LOOP COULD BE OPTIMISED BY USING POS TO LEAP TO NEXT MODE
   FOR II FROM 1 TO SIZE(LST) DO
    IF LST(II)==ITEM THEN
     LSTPOSNS(0):=II;
    END;//IF 
   END;//FOR
  END;//IF
  //Return Positions that match ITEM
  RETURN LSTPOSNS;
 END;

 EXPORT ListHEAD(LST)
 //List HEAD AKA LISP CAR
 BEGIN
  RETURN LST(1);
 END;

 EXPORT ListINDEX(LST,ITEM)
 //Simple: Return posn of item
 BEGIN
  RETURN POS(LST,ITEM);
 END;

 EXPORT ListINSERT(LST,POSN,ITEM)
 //INSERT ITEM BEFORE POSN
 //PPL POSN=0 = APPEND
 //Py  POSN=0 = 1ST
 BEGIN
  LOCAL POSNB:=POSN-1;
  LOCAL LSTB:=IFTE(POSN==1,{},LST({1,POSNB}));
  LOCAL LSTA:=LST({POSN,SIZE(LST)});

  IF POSN==0 THEN //IN PPL:
   //TBD();
   RETURN CONCAT(LST,ITEM);
  END;
  RETURN CONCAT(CONCAT(LSTB,ITEM),LSTA);
 END;

 EXPORT ListIsLIST(LST)
 //In PPL lists and sets both 1
 BEGIN
   RETURN (TYPE(LST)==ListTYPE);
 END;

 EXPORT ListIsSET(LST)
 //A uniquelist (no duplicates) may be a set
 BEGIN
  RETURN NOT(ListCOUNTANYDUPLICATES(LST));
 END;

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

 EXPORT ListMASKBOOL(LST,LSTBOOL,NewValue)
 //Mask selected values
 //Cf ANDBOOL
 //Here 1 selects replace, not 0
 BEGIN 
  //Guard against empty "" giving syn err
  LOCAL MYNULL:=IFTE(NewValue=="","CHAR(0)",NewValue);

  RETURN EXECON("IFTE(&2,"+MYNULL+",&1)",LST,LSTBOOL);
 
  //Equivalent to
  //RETURN ListANDBOOL(LST,NOT(LSTBOOL),NewValue);
 END;

 EXPORT ListOCCURRENCES(LST)
 //Given a list
 //Return unique list of occurrences and their occurrence counts as 2 lists
 BEGIN
  LOCAL II;
  LOCAL LSTF:={};
  LOCAL LSTV:=ListREMOVEDUPLICATES(LST);

  FOR II FROM 1 TO SIZE(LSTV) DO
   LSTF(II):=ListCOUNT(LST,LSTV(II));
  END;
  RETURN {LSTV,LSTF};
 END;

 EXPORT ListPOP(LST,POSN)
 //POP POSN OFF LIST
 BEGIN
  LOCAL ITEM;
  IF SIZE(LST) THEN
   ITEM:=LST(IFTE(POSN,POSN,SIZE(LST)));//0=>LAST
   ListANS:=ListREMOVEX(LST,POSN);
  ELSE
   RAISE(ListIsEmptyError,"ListPOP",1);
   ITEM:={};
   ListANS:={};
  END;   
  //RETURN POPPED ITEM
  //BUT ALSO SAVE SHORTENED LST
  RETURN ITEM;
 END;

 EXPORT ListPOPLAST(LST)
 //POP POSN OFF LIST
 //Py: POP()
 BEGIN
  RETURN ListPOP(LST,SIZE(LST)); 
 END;

 EXPORT ListremoveX(LST,POSN)
 // CAS ALTERNATIVE TO REMOVEX:MAY BE SLOW
 //See 
 //http://www.hpmuseum.org/forum/thread-9406.html and
 //http://www.hpmuseum.org/forum/thread-7987.html?highlight=suppress 
 BEGIN
  RETURN suppress(LST,POSN);
 END;

 EXPORT ListREMOVEX(LST,POSN)
 //REMOVE 1 ITEM AT POSN
 BEGIN
  LOCAL LSTB,LSTA;

  IF POSN THEN
   LSTB:=ListBEFORE(LST,POSN);
   LSTA:=ListAFTER (LST,POSN);
   RETURN CONCAT(LSTB,LSTA);//THIS
  ELSE
   //PPL: 0=Remove Last Item
   RETURN ListREMOVEX(LST,SIZE(LST));
   //Py: 0=RemoveFirst ie return TAIL
  END;
 END;

 EXPORT ListREMOVE(LST,ITEM)
 //Remove 1 instance of ITEM 
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  IF POSN THEN
   RETURN ListREMOVEX(LST,POSN);
  END;
  RAISE(ItemNotFoundError,ITEM,0);
  RETURN LST;//NOTHING TO REMOVE
 END;

 EXPORT ListREMOVEDUPLICATES(LST)
 //RESULT WITH DUPLICATES JUST ONCE 
 //Native: Sequence NOT determined but seems same
 //From #21
 BEGIN
  RETURN UNION(LST);
 END;

 EXPORT ListREMOVEDUPLICATESSL(LST)
 //SL
 //My own implementation ensures known list sequence (per original LST)
 BEGIN
  LOCAL II;
  LOCAL ListANS:={};

  FOR II FROM 1 TO SIZE(LST)  DO
   IF POS(ListANS,LST(II))==0 THEN //NOT YET LISTED
    ListANS(0):=LST(II);//ADD ENTRY
   END;
  END;
  RETURN ListANS;//EACH ITEM ONCE
 END;

 EXPORT ListSLICE(LST,FRM,TOO)
 //RETURN PART OF LIST
 //SYNTAX HINT
 //SUGGEST ALSO IMPL (LST,{2,3})
 //FRM≤TOO:Bad Inputs={}
 BEGIN
  LOCAL TTOO:=IFTE(TOO==0,SIZE(LST),TOO); //TO 0==LAST
  LOCAL TFRM:=IFTE(FRM==0,SIZE(LST),FRM); //FRM 0==LAST
  //MSGBOX("SLICE "+{FRM,TOO});
  IF TFRM>TTOO THEN
    RAISE(IndexOutOfBoundsException,FRM,1);//Maybe a new error
    RETURN {};
  END; 
  RETURN LST({TFRM,TTOO});
 END;

 EXPORT ListSORT(LST)
 //This implementation uses native SORT
 //On old compilers See known bugs 
 //This will not affect MODE other than changing ordering 
 BEGIN
  RETURN SORT(LST);
 END;

 EXPORT ListTAIL(LST)
 //List TAIL AKA LISP CDR
 BEGIN
  RETURN LST({2,SIZE(LST)});
 END;

 EXPORT ListToSET(LST)
 //In addition to making the list like a set
 //wibni we could track those tnat ARE sets
 BEGIN
  RETURN ListREMOVEDUPLICATES(LST);
 END;

 EXPORT ListVERSION()
 BEGIN
  RETURN CRID;
 END;

 
 //STATISTICAL LIST FUNCTIONS

 EXPORT ListMEAN(LST)
 BEGIN
  IF SIZE(LST) THEN
   RETURN mean(LST);
  END;
  RAISE(ListIsEmptyError,"MEAN",1);
  RETURN {};
 END;

 EXPORT ListMEAN2(LSTV,LSTF)
 BEGIN
  IF SIZE(LSTV) AND SIZE(LSTF) THEN
   RETURN mean(LSTV,LSTF);
  END;
  RAISE(ListIsEmptyError,"MEAN",1);
  RETURN {};
 END;

 EXPORT ListMEDIAN(LST)
 BEGIN
  IF SIZE(LST) THEN
   RETURN(median(LST));
  END;
  RAISE(ListIsEmptyError,"MEDIAN",1);//(NO MEDIAN)
  RETURN {};///
 END;

 EXPORT ListMEDIAN2(LSTV,LSTF)
 BEGIN
  IF SIZE(LSTV) AND SIZE(LSTF) THEN
   RETURN(median(LSTV,LSTF));
  END;
  RAISE(ListIsEmptyError,"MEDIAN",1);
  RETURN {};///
 END;

 EXPORT ListMODES2(LSTV,LSTF)
 //Get MODES of ItemXFrequency Lists
 //Empty=Empty
 BEGIN
  LOCAL II;
  LOCAL MODESLST:={};
  LOCAL MODEPOSNS:={};

  IF SIZE(LSTF) AND SIZE(LSTV) THEN
   //Find MODES
   MODEPOSNS:=ListFIND(LSTF,MAX(LSTF));
  
   FOR II FROM 1 TO SIZE(MODEPOSNS) DO
    MODESLST(II):=LSTV(MODEPOSNS(II));
   END;//FOR
  END;//IF
  RETURN MODESLST;
 END;

 EXPORT ListMODES(LST)
 //Get MODES of LST : Empty = Empty
 BEGIN
  //Make uniquelst and count
  ListANS:=ListOCCURRENCES(LST);
  
  RETURN ListMODES2(ListANS(1),ListANS(2));
 END;


 // Python names(LC) prefixed Py ()
 // Py  syntax: Lst.append(ITEM) etc 
 // PPL syntax: Lst:=append(Lst,ITEM)
 // Py indexes from 0 but not yet implemented
 // These names are inspired by Py, 
 // but will never provide exact equivalents.
 
 EXPORT Pyappend(LST,ITEM)
 BEGIN 
  RETURN append(LST,ITEM);//CAS
 END;

 EXPORT Pyclear(LST)
 //Py :ALSO DELETES LIST (cf CAS purge)
 BEGIN 
  RETURN {};
 END;

 EXPORT Pycopy(LST)
 //Py: A shallow copy PPL: simple copy
 BEGIN
  RETURN LST;
 END;

 EXPORT Pycount(LST,ITEM)
 //Py :Count occurences of item
 BEGIN
  RETURN ListCOUNT(LST,ITEM);
 END;

 EXPORT Pyextend(LST,LST2)
 //Py :Concat items in LST2 to LST
 //ALL ITEMS FROM LST2 ARE ADDED
 //=IF FULL FAIL ADDING NONE?
 //PPL:LST2 may be an item 
 BEGIN
  CONCAT(LST,LST2);
 END;

 EXPORT Pyindex(LST,ITEM)
 //Py :Return index (or ValueErr)

 //TBD START:END LIMIT RANGE SEARCHED WITHOUT CHANGING INDEX
 BEGIN
  LOCAL LX:=ListINDEX(LST,ITEM); 
  IF LX==0 THEN
   RAISE(ValueError,ITEM,1);//Py:NotFound => an error
  END;
  RETURN LX; 
 END;

 EXPORT Pyinsert(LST,POSN,ITEM)
 //Py :Insert ITEM before POS
 BEGIN
  IF POSN==0 THEN
   TBD();
   CONCAT(ITEM,LST);//Py 0
  END;
  RETURN ListINSERT(LST,POSN,ITEM); 
 END;

 EXPORT Pypop(LST,POSN)
 //Py :Pop item (Posn Omit:Last)
 //PPL:Posn reqd
 BEGIN
  IF POSN==0 THEN
   TBD();
  END;
  RETURN ListPOP(LST,POSN);
 END;

 EXPORT PypopLast(LST)
 //Py :Pop item (Posn Omit:Last)
 //PPL:Twofunctions
 BEGIN
  RETURN ListPOPLAST(LST);
 END;

 EXPORT Pyremove(LST,ITEM)
 //Py :Remove 1st ITEM,ERR IF NONE
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  IF POSN THEN
   RETURN ListREMOVEX(LST,POSN);
  END;
  //ELSE NOTHING TO REMOVE
  RAISE(ItemNotFoundError,ITEM,1);
  RETURN LST;
 END;
 
 EXPORT Pyreverse (LST)
 BEGIN
  RETURN REVERSE(LST);
 END;

 EXPORT Pysort(LST,KeyFunc,RReverse)
 //TBD: KeyFunc: Selects sort key from itapprox()
 BEGIN
  RETURN IFTE(RReverse,Pyreverse(LST),SORT(LST));

 END;

 EXPORT ListPythonAnalogues ()
 BEGIN
  LOCAL KK;
  LOCAL PyFuns:={"Pyappend",
   "Pyclear","Pycopy","Pycount",
   "Pyextend",
   "Pyindex","Pyinsert",
   "Pypop","Pypoplast",
   "Pyremove","Pyreverse",
   "Pysort"};
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,"Py analogues",PyFuns)

 END;

 EXPORT ListStatisticalFunctions()
 BEGIN
  LOCAL KK;
  CHOOSE(KK,"Statistical Functions",
   {"ListMEAN","ListMEAN2",
    "ListMEDIAN","ListMEDIAN2",
    "ListMODES","ListMODES2"});
 END;

 EXPORT ListExamples()
 //In real use, use XXX:=List...()
 BEGIN
  LOCAL LL:={1,2,3,4,5,6,7,8,9};
  PRINT();
  PRINT(ListVERSION);
  //PRINT("A");
  PRINT(ListAFTER(LL,2));
  PRINT(ListANDBOOL({1,12},{0,1},"122"));
  PRINT(ListANDBOOL({"AA","BB"},{0,1},"CHAR(0)"));
  PRINT(ListBEFORE(LL,2));
  //PRINT("C");
  PRINT(ListCOUNT({},2));
  PRINT(ListCOUNTANYDUPLICATES_SORTED({}));
  PRINT(ListCOUNTANYDUPLICATES({0,2,2,2}));
  //PRINT("F");
  PRINT(ListFIND(LL,2));
  PRINT(ListHEAD(LL));
  PRINT(ListINDEX(LL,2));
  PRINT(ListINSERT(LL,2,4));
  PRINT(ListIsLIST(5));
  PRINT(ListIsSET(LL));
  PRINT(ListIsSORTED(LL)); 
  PRINT(ListMASKBOOL({1,12},{0,1},"122"));
  PRINT(ListMASKBOOL({"AA","BB"},{0,1},"CHAR(0)"));
  PRINT(ListOCCURRENCES(LL));
  PRINT(ListPOP(LL,2));LL:=ListANS;
  PRINT(ListPOPLAST(LL));LL:=ListANS;
  PRINT(ListREMOVEX(LL,2));
  PRINT(ListREMOVE(LL,9));
  PRINT(ListSLICE({1,2,3,4},2,3));
  PRINT(ListSORT(LL));
  PRINT(ListTAIL(LL));
  PRINT(ListToSET({1,2,2}));
 
  PRINT(ListMEAN(LL));
  PRINT(ListMEDIAN(LL));
  PRINT(ListMODES({"AC","DC"})); 
 
  PRINT("Exampled");
  //RETURN ListCOUNT({1,2,2,2},2);
 END;

 EXPORT LIST()
 BEGIN
  ABOUT();
  //ListExamples();
 END;

Version 0.03

Code:

   
 LOCAL CRID:="List API V0.02++ © 2017 StephenG1CMZ";

 //Customise
 EXPORT ListErrShow:=1;//SHOW ERRORS
 //End

 //Forward
 ListCOUNTITEM(LST,ITEM);
 ListCOUNTITEMS(LST,ITEMS);
 ListREMOVEDUPLICATES(LST);
 ListREMOVEX(LST,POSN);
 ListSORT(LST);


 //NB In main routines (ie not Python)
 //POSN parameter is >=0 (0=LAST)
 //POSN returned is ≥0 (PPL,0=NOTIN)

 //LOCAL SL:=1;
 LOCAL NL:="\n";

 EXPORT ListTYPE:=6;//MAGIC NUMBER FOR LISTS.Exported to avoid magic

 LOCAL ListANS;//OUTPUT LIST(WHEN NOT RETURNED)
  //Also, useful temporary results 

 //ERR 
 LOCAL ListLastError:=0;
 LOCAL ERRLST:={
  "IndexOutofBoundsException",
  "ListIsEmptyError",
  "ListStatisticsError",
  "Py: ItemNotFoundError",
  "Py: ValueError"
 };
 //ERRNO IS ARBITRARY:INDEXES ERRLST
 LOCAL IndexOutOfBoundsException:=1;
 LOCAL ListIsEmptyError:=2;
 LOCAL ListStatisticsError:=3;//
 LOCAL ItemNotFoundError:=4;
 LOCAL ValueError:=5; 
 
 EXPORT ABOUT()
 BEGIN
  MSGBOX(CRID);
 END;

 TBD()
 BEGIN
  MSGBOX( "List: TBD");
 END;

 EXPORT RAISE(ERR,CULPRIT,SEVERITY)
 //Only exported for testing
 BEGIN
  IF ListErrShow AND SEVERITY THEN
   MSGBOX("List: "+ERRLST(ERR)+NL+CULPRIT);
  END;
  ListLastError:=ERR;
 END;

 //MAINLY STANDARD FUNCTIONS

 EXPORT ListAFTER(LST,POSN)
 //Slice After POSN:
 //POSN=0 OR LAST:{}
 BEGIN
  LOCAL FRM:=POSN+1;
  RETURN IFTE((POSN==0 OR FRM>SIZE(LST)),{},LST({FRM,SIZE(LST)}));
 END;

 EXPORT ListANDBOOL(LST,LSTBOOL,NewValue)
 //Replace items ANDed out with NULL(NewValue)
 //EG ({"AA","BB"},{0,1},"CHAR(0)") = {"","BB"}//Note the quotes
 //EG ({11,13},{0,1},"12")//NOMORETHAN12
 //RequirementSpec:
 //http://www.hpmuseum.org/forum/thread-5092.html
 //Usage:
 //http://www.hpmuseum.org/forum/thread-5031.html
 //See also:MaskBOOL
 //NULL=NULL
 BEGIN
  //Guard against empty "" giving syn err
  LOCAL MYNULL:=IFTE(NewValue=="","CHAR(0)",NewValue);
  IF SIZE(LST) AND SIZE(LSTBOOL) THEN
   RETURN EXECON("IFTE(&2,&1,"+MYNULL+")",LST,LSTBOOL);
  END;
  RETURN {};
 END;

 EXPORT ListAPPEND(LST,ITEM)
 //APPEND ITEM TO LIST
 //EG L2:=APPEND(L2,3)
 //PPL:L2(0):=3;
 //Py:APPEND(L2,3)
 //NULL: {ITEM}
 // (LST,{ITEMLST}) ADDS 1 ITEM (A LST)
 BEGIN
  RETURN LST(0):=ITEM; 
 END;

 EXPORT ListBEFORE(LST,POSN)
 //Slice Before POSN: 
 //POSN=0: ({1,2},0)={1}
 BEGIN
  LOCAL TOO:=POSN-1;
  IF POSN==0 THEN
    RETURN ListBEFORE(LST,SIZE(LST));
  END;
  RETURN IFTE(TOO>0,LST({1,TOO}),{});
 END;

 EXPORT ListCONCAT(LST1,LST2)
 //CONCATENATE
 BEGIN
  CONCAT(LST1,LST2);
 END;

 EXPORT ListCOUNT (LST,ITEM)
 //COUNT 1 ITEM:FASTEST
  //INTERSECT IS CURRENTLY QUICKER
  //BUT RECHECK AFTER ITERATIVE SOLN IMPL
 BEGIN
  RETURN ListCOUNTITEMS(LST,{ITEM});
 END;

 EXPORT ListCOUNTANYDUPLICATES(LST)
 //Current Implementation yields a sorted LST
 //But might change
 BEGIN
  ListANS:=ListSORT(LST);
  RETURN ListCOUNTANYDUPLICATES_SORTED(ListANS);
 END;

 EXPORT ListCOUNTANYDUPLICATES_SORTED(SortedLST)
 //Count how many duplicates in a sortedlist,Return a REAL INT
 //({1,9,9}=1 dup, {1,2,2,3,3,3}=3 dup)
 BEGIN
  LOCAL II;
  LOCAL DUPCOUNT:=0;
  IF SIZE(SortedLST)>1 THEN
   FOR II FROM 1 TO SIZE(SortedLST)-1 DO
    IF SortedLST(II) ==SortedLST(II+1) THEN
     DUPCOUNT:=DUPCOUNT+1;
    END;//IF
   END;//FOR
   //ELSE:SMALL LISTS HAVE NO DUPLICATES
  END;//IF
  RETURN DUPCOUNT;
 END;

 
 EXPORT ListCOUNTITEM(LST,ITEM)
 //Count Instances of 1 ITEM in LST
 //ITEM MAY BE A LIST COMPRISING 1 ITEM 
 //(USE COUNTITEMS TO SEARCH FOR A LIST OF ITEMS)
 //NULL LST:0
 //NULL ITEM:COUNTED
 
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  CASE
   IF POSN==0 THEN RETURN 0; END;
   //IF POSN==SIZE(LST)  THEN RETURN 1; END;
   DEFAULT
    //FOR LISTS WIH MANY DUPLICATES:
    //AN ITERATIVE SOLN WILL BE NEEDED
    RETURN 1+ListCOUNT(ListAFTER(LST,POSN),ITEM);
  END; 
 END;

 EXPORT ListCOUNTITEMS(LST,ITEMS)
 //ITEMS MAY BE 1 ITEM OR A LIST OF SEPARATE ITEMS
 //SO TO COUNT LISTS, CONTAIN THEM IN A LIST
 //EG {1,{},2},{{}}= 1
 //EG {1,2,3},{2,3} = 2
 //EG {1,{2,3}},{2,3} = 0 (TO SEARCH FOR ITEM {2,3} USE COUNT)
 //ITEMS NULL=0
 //THIS VERSION IS QUICKER,BUT PARAMETERS DIFFER
 BEGIN
  RETURN SIZE(INTERSECT(LST,ITEMS));
 END;

 EXPORT ListFIND(LST,ITEM)
 //Find all instances of ITEM
 BEGIN
  LOCAL II;
  LOCAL LSTPOSNS:={};

  IF SIZE(LST) THEN //
   //LOOP COULD BE OPTIMISED BY USING POS TO LEAP TO NEXT MODE
   FOR II FROM 1 TO SIZE(LST) DO
    IF LST(II)==ITEM THEN
     LSTPOSNS(0):=II;
    END;//IF 
   END;//FOR
  END;//IF
  //Return Positions that match ITEM
  RETURN LSTPOSNS;
 END;

 EXPORT ListHEAD(LST)
 //List HEAD AKA LISP CAR
 //NULL:ERR
 BEGIN
  IF SIZE(LST) THEN
   RETURN LST(1);
  END;
  RAISE(ListIsEmptyError,"HEAD",1);
  RETURN {};
 END;

 EXPORT ListINDEX(LST,ITEM)
 //Simple: Return posn of item
 //
 BEGIN
  RETURN POS(LST,ITEM);
 END;

 EXPORT ListINSERT(LST,POSN,ITEM)
 //INSERT ITEM BEFORE POSN
 //PPL POSN=0 = APPEND
 //Py  POSN=0 = 1ST
 BEGIN
  LOCAL POSNB:=POSN-1;
  LOCAL LSTB:=IFTE(POSN==1,{},LST({1,POSNB}));
  LOCAL LSTA:=LST({POSN,SIZE(LST)});

  IF POSN==0 THEN //IN PPL:
   //TBD();
   RETURN CONCAT(LST,ITEM);
  END;
  RETURN CONCAT(CONCAT(LSTB,ITEM),LSTA);
 END;

 EXPORT ListIsLIST(LST)
 //In PPL lists and sets both 1
 BEGIN
   RETURN (TYPE(LST)==ListTYPE);
 END;

 EXPORT ListIsSET(LST)
 //A uniquelist (no duplicates) may be a set
 BEGIN
  RETURN NOT(ListCOUNTANYDUPLICATES(LST));
 END;

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

 EXPORT ListMASKBOOL(LST,LSTBOOL,NewValue)
 //Mask selected values
 //Cf ANDBOOL
 //Here 1 selects replace, not 0
 //NULL=NULL
 BEGIN 
  //Guard against empty "" giving syn err
  LOCAL MYNULL:=IFTE(NewValue=="","CHAR(0)",NewValue);
  IF SIZE(LST) AND SIZE(LSTBOOL) THEN
   RETURN EXECON("IFTE(&2,"+MYNULL+",&1)",LST,LSTBOOL);
  END;
  RETURN {};
  //Equivalent to
  //RETURN ListANDBOOL(LST,NOT(LSTBOOL),NewValue);
 END;

 EXPORT ListMEAN(LST)
 BEGIN
  IF SIZE(LST) THEN
   RETURN mean(LST);
  END;
  RAISE(ListIsEmptyError,"MEAN",1);
  RETURN {};
 END;

 EXPORT ListMEAN2(LSTV,LSTF)
 BEGIN
  IF SIZE(LSTV) AND SIZE(LSTF) THEN
   RETURN mean(LSTV,LSTF);
  END;
  RAISE(ListIsEmptyError,"MEAN",1);
  RETURN {};
 END;

 EXPORT ListMEDIAN(LST)
 BEGIN
  IF SIZE(LST) THEN
   RETURN(median(LST));
  END;
  RAISE(ListIsEmptyError,"MEDIAN",1);//(NO MEDIAN)
  RETURN {};///
 END;

 EXPORT ListMEDIAN2(LSTV,LSTF)
 BEGIN
  IF SIZE(LSTV) AND SIZE(LSTF) THEN
   RETURN(median(LSTV,LSTF));
  END;
  RAISE(ListIsEmptyError,"MEDIAN",1);
  RETURN {};///
 END;

 EXPORT ListMODE2(LSTV,LSTF)
 //Get MODES of ItemXFrequency Lists
 //Empty=Empty
 BEGIN
  LOCAL II;
  LOCAL MODESLST:={};
  LOCAL MODEPOSNS:={};

  IF SIZE(LSTF) AND SIZE(LSTV) THEN
   //Find MODES
   MODEPOSNS:=ListFIND(LSTF,MAX(LSTF));
  
   FOR II FROM 1 TO SIZE(MODEPOSNS) DO
    MODESLST(II):=LSTV(MODEPOSNS(II));
   END;//FOR
  END;//IF
  RETURN MODESLST;
 END;

 EXPORT ListMODE(LST)
 //Get MODES of LST : Empty = Empty
 BEGIN
  //Make uniquelst and count
  ListANS:=ListOCCURRENCES(LST);
  
  RETURN ListMODE2(ListANS(1),ListANS(2));
 END;

 EXPORT ListOCCURRENCES(LST)
 //Given a list
 //Return unique list of occurrences and their occurrence counts as 2 lists
 BEGIN
  LOCAL II;
  LOCAL LSTF:={};
  LOCAL LSTV:=ListREMOVEDUPLICATES(LST);

  FOR II FROM 1 TO SIZE(LSTV) DO
   LSTF(II):=ListCOUNT(LST,LSTV(II));
  END;
  RETURN {LSTV,LSTF};
 END;

 EXPORT ListInvOCCUR(LSTV,LSTF)
 //INVERSE OF OCCURRENCES
 //Given V and F yield V,F times
 //NULL=NULL
 //In an OCCURRENCES list V is unique and F>0
 //But We handle V with F=0 and V nonunique
 BEGIN
  LOCAL II,JJ;
  LOCAL LST:={};

  FOR II FROM 1 TO SIZE(LSTV) DO
   IF LSTF(II) THEN //V WITH F>0
    LST:=CONCAT(LST,MAKELIST(LSTV(II),JJ,1,LSTF(II)));
   END;
  END;
 
  RETURN LST;
 END;

 EXPORT ListPOP(LST,POSN)
 //POP POSN OFF LIST
 BEGIN
  LOCAL ITEM;
  IF SIZE(LST) THEN
   ITEM:=LST(IFTE(POSN,POSN,SIZE(LST)));//0=>LAST
   ListANS:=ListREMOVEX(LST,POSN);
  ELSE
   RAISE(ListIsEmptyError,"ListPOP",1);
   ITEM:={};
   ListANS:={};
  END;   
  //RETURN POPPED ITEM
  //BUT ALSO SAVE SHORTENED LST
  RETURN ITEM;
 END;

 EXPORT ListPOPLAST(LST)
 //POP POSN OFF LIST
 //Py: POP()
 BEGIN
  RETURN ListPOP(LST,SIZE(LST)); 
 END;

 EXPORT ListremoveX(LST,POSN)
 // CAS ALTERNATIVE TO REMOVEX:MAY BE SLOW
 //See 
 //http://www.hpmuseum.org/forum/thread-9406.html and
 //http://www.hpmuseum.org/forum/thread-7987.html?highlight=suppress 
 //NULL=NUL,POSN>SZE=LST
 BEGIN
  IF POSN THEN
   RETURN suppress(LST,POSN);
  END;
  RETURN suppress(LST,SIZE(LST));//0=LAST
 END;

 EXPORT ListREMOVEX(LST,POSN)
 //REMOVE 1 ITEM AT POSN
 //NULL=NULL,POSN>SIZE=LST
 BEGIN
  LOCAL LSTB,LSTA;

  IF POSN THEN
   LSTB:=ListBEFORE(LST,POSN);
   LSTA:=ListAFTER (LST,POSN);
   RETURN CONCAT(LSTB,LSTA);//THIS
  ELSE
   //PPL: 0=Remove Last Item
   RETURN ListREMOVEX(LST,SIZE(LST));
   //Py: 0=RemoveFirst ie return TAIL
  END;
 END;
 
 EXPORT Listremove(LST,ITEM) 
 //CAS version slower
 //NULL=NULL
 BEGIN
  RETURN remove(ITEM,LST);
 END;

 EXPORT ListREMOVE(LST,ITEM)
 //Remove 1 instance of ITEM
 //NULL=NULL 
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  IF POSN THEN
   RETURN ListREMOVEX(LST,POSN);
  END;
  RAISE(ItemNotFoundError,ITEM,0);
  RETURN LST;//NOTHING TO REMOVE
 END;

 EXPORT ListREMOVEDUPLICATES(LST)
 //RESULT WITH DUPLICATES JUST ONCE 
 //Native: Sequence NOT determined but seems same
 //From #21
 BEGIN
  RETURN UNION(LST);
 END;

 EXPORT ListREMOVEDUPLICATESSL(LST)
 //SL
 //My own implementation ensures known list sequence (per original LST)
 BEGIN
  LOCAL II;
  LOCAL ListANS:={};

  FOR II FROM 1 TO SIZE(LST)  DO
   IF POS(ListANS,LST(II))==0 THEN //NOT YET LISTED
    ListANS(0):=LST(II);//ADD ENTRY
   END;
  END;
  RETURN ListANS;//EACH ITEM ONCE
 END;

 EXPORT ListSLICE(LST,FRM,TOO)
 //RETURN PART OF LIST
 //SYNTAX HINT
 //SUGGEST ALSO IMPL (LST,{2,3})
 //FRM≤TOO:Bad Inputs={}
 BEGIN
  LOCAL TTOO:=IFTE(TOO==0,SIZE(LST),TOO); //TO 0==LAST
  LOCAL TFRM:=IFTE(FRM==0,SIZE(LST),FRM); //FRM 0==LAST
  //MSGBOX("SLICE "+{FRM,TOO});
  IF TFRM>TTOO THEN
    RAISE(IndexOutOfBoundsException,FRM,1);//Maybe a new error
    RETURN {};
  END; 
  RETURN LST({TFRM,TTOO});
 END;

 EXPORT ListSORT(LST)
 //This implementation uses native SORT
 //On old compilers See known bugs 
 //This will not affect MODE other than changing ordering 
 BEGIN
  RETURN SORT(LST);
 END;

 EXPORT ListTAIL(LST)
 //List TAIL AKA LISP CDR
 //NULL:ERR
 BEGIN
  IF SIZE(LST) THEN
   RETURN LST({2,SIZE(LST)});
  END;
  RAISE(ListIsEmptyError,"TAIL",1);
  RETURN {};
 END;

 EXPORT ListToSET(LST)
 //In addition to making the list like a set
 //wibni we could track those tnat ARE sets
 BEGIN
  RETURN ListREMOVEDUPLICATES(LST);
 END;

 EXPORT ListVERSION()
 BEGIN
  RETURN CRID;
 END;

 // Python names(LC) prefixed Py ()
 // Py  syntax: Lst.append(ITEM) etc 
 // PPL syntax: Lst:=append(Lst,ITEM)
 // Py indexes from 0 but not yet implemented
 // These names are inspired by Py, 
 // but will never provide exact equivalents.
 
 EXPORT Pyappend(LST,ITEM)
 BEGIN 
  RETURN append(LST,ITEM);//CAS
 END;

 EXPORT Pyclear(LST)
 //Py :ALSO DELETES LIST (cf CAS purge)
 BEGIN 
  RETURN {};
 END;

 EXPORT Pycopy(LST)
 //Py: A shallow copy PPL: simple copy
 BEGIN
  RETURN LST;
 END;

 EXPORT Pycount(LST,ITEM)
 //Py :Count occurences of item
 BEGIN
  RETURN ListCOUNT(LST,ITEM);
 END;

 EXPORT Pyextend(LST,LST2)
 //Py :Concat items in LST2 to LST
 //ALL ITEMS FROM LST2 ARE ADDED
 //=IF FULL FAIL ADDING NONE?
 //PPL:LST2 may be an item 
 BEGIN
  CONCAT(LST,LST2);
 END;

 EXPORT Pyindex(LST,ITEM)
 //Py :Return index (or ValueErr)

 //TBD START:END LIMIT RANGE SEARCHED WITHOUT CHANGING INDEX
 BEGIN
  LOCAL LX:=ListINDEX(LST,ITEM); 
  IF LX==0 THEN
   RAISE(ValueError,ITEM,1);//Py:NotFound => an error
  END;
  RETURN LX; 
 END;

 EXPORT Pyinsert(LST,POSN,ITEM)
 //Py :Insert ITEM before POS
 BEGIN
  IF POSN==0 THEN
   TBD();
   CONCAT(ITEM,LST);//Py 0
  END;
  RETURN ListINSERT(LST,POSN,ITEM); 
 END;

 EXPORT Pypop(LST,POSN)
 //Py :Pop item (Posn Omit:Last)
 //PPL:Posn reqd
 BEGIN
  IF POSN==0 THEN
   TBD();
  END;
  RETURN ListPOP(LST,POSN);
 END;

 EXPORT PypopLast(LST)
 //Py :Pop item (Posn Omit:Last)
 //PPL:Twofunctions
 BEGIN
  RETURN ListPOPLAST(LST);
 END;

 EXPORT Pyremove(LST,ITEM)
 //Py :Remove 1st ITEM,ERR IF NONE
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  IF POSN THEN
   RETURN ListREMOVEX(LST,POSN);
  END;
  //ELSE NOTHING TO REMOVE
  RAISE(ItemNotFoundError,ITEM,1);
  RETURN LST;
 END;
 
 EXPORT Pyreverse (LST)
 BEGIN
  RETURN REVERSE(LST);
 END;

 EXPORT Pysort(LST,KeyFunc,RReverse)
 //TBD: KeyFunc: Selects sort key from itapprox()
 BEGIN
  RETURN IFTE(RReverse,Pyreverse(LST),SORT(LST));

 END;

 EXPORT ListPythonAnalogues ()
 BEGIN
  LOCAL KK;
  LOCAL PyFuns:={"Pyappend",
   "Pyclear","Pycopy","Pycount",
   "Pyextend",
   "Pyindex","Pyinsert",
   "Pypop","Pypoplast",
   "Pyremove","Pyreverse",
   "Pysort"};
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,"Py analogues",PyFuns)

 END;

 EXPORT ListStatisticalFunctions()
 BEGIN
  LOCAL KK;
  //Just listed to group these Not choosable
  CHOOSE(KK,"Statistical Functions",
   {"ListMEAN","ListMEAN2",
    "ListMEDIAN","ListMEDIAN2",
    "ListMODE","ListMODE2"});
 END;

 EXPORT ListExamples()
 //In real use, use XXX:=List...()
 BEGIN
  LOCAL LL:={1,2,3,4,5,6,7,8,9};
  PRINT();
  PRINT(ListVERSION);
  //PRINT("A");
  PRINT(ListAFTER(LL,2));
  PRINT(ListANDBOOL({1,12},{0,1},"122"));
  PRINT(ListANDBOOL({"AA","BB"},{0,1},"CHAR(0)"));
  PRINT(ListBEFORE(LL,2));
  //PRINT("C");
  PRINT(ListCOUNT({},2));
  PRINT(ListCOUNTANYDUPLICATES_SORTED({}));
  PRINT(ListCOUNTANYDUPLICATES({0,2,2,2}));
  //PRINT("F");
  PRINT(ListFIND(LL,2));
  PRINT(ListHEAD(LL));
  PRINT(ListINDEX(LL,2));
  PRINT(ListINSERT(LL,2,4));
  PRINT(ListIsLIST(5));
  PRINT(ListIsSET(LL));
  PRINT(ListIsSORTED(LL)); 
  PRINT(ListMASKBOOL({1,12},{0,1},"122"));
  PRINT(ListMASKBOOL({"AA","BB"},{0,1},"CHAR(0)"));
  PRINT(ListOCCURRENCES(LL));
  PRINT(ListPOP(LL,2));LL:=ListANS;
  PRINT(ListPOPLAST(LL));LL:=ListANS;
  PRINT(ListREMOVEX(LL,2));
  PRINT(ListREMOVE(LL,9));
  PRINT(ListSLICE({1,2,3,4},2,3));
  PRINT(ListSORT(LL));
  PRINT(ListTAIL(LL));
  PRINT(ListToSET({1,2,2}));
 
  PRINT(ListMEAN(LL));
  PRINT(ListMEDIAN(LL));
  PRINT(ListMODES({"AC","DC"})); 
 
  PRINT("Exampled");
  //RETURN ListCOUNT({1,2,2,2},2);
 END;

 EXPORT LIST()
 BEGIN
  ABOUT();
  //ListExamples();
 END;

Version 0.04

Code:


 LOCAL CRID:="List API V0.04 © 2017 StephenG1CMZ";

 //Customise
 EXPORT ListErrShow:=1;//SHOW ERRORS
 //End

 //Forward
 ListCOUNTITEM(LST,ITEM);
 ListCOUNTITEMS(LST,ITEMS);
 ListREMOVEDUPLICATES(LST);
 ListREMOVEX(LST,POSN);
 ListSORT(LST);


 //NB In main routines (ie not Python)
 //POSN parameter is >=0 (0=LAST)
 //POSN returned is ≥0 (PPL,0=NOTIN)

 //LOCAL SL:=1;
 LOCAL NL:="\n";

 EXPORT ListTYPE:=6;//MAGIC NUMBER FOR LISTS.Exported to avoid magic
 LOCAL NumTYPE:=0;
 LOCAL ListANS;//OUTPUT LIST(WHEN NOT RETURNED)
  //Also, useful temporary results 

 //ERR 
 LOCAL ListLastError:=0;
 LOCAL ERRLST:={
  "IndexOutofBoundsException",
  "ListIsEmptyError",
  "ListStatisticsError",
  "Py: ItemNotFoundError",
  "Py: ValueError"
 };
 //ERRNO IS ARBITRARY:INDEXES ERRLST
 LOCAL IndexOutOfBoundsException:=1;
 LOCAL ListIsEmptyError:=2;
 LOCAL ListStatisticsError:=3;//
 LOCAL ItemNotFoundError:=4;
 LOCAL ValueError:=5; 
 
 EXPORT ABOUT()
 BEGIN
  MSGBOX(CRID);
 END;

 TBD()
 BEGIN
  MSGBOX( "List: TBD");
 END;

 EXPORT RAISE(ERR,CULPRIT,SEVERITY)
 //Only exported for testing
 BEGIN
  IF ListErrShow AND SEVERITY THEN
   MSGBOX("List: "+ERRLST(ERR)+NL+CULPRIT);
  END;
  ListLastError:=ERR;
 END;

 //MAINLY STANDARD FUNCTIONS

 EXPORT ListAFTER(LST,POSN)
 //Slice After POSN:
 //POSN=0 OR LAST:{}
 BEGIN
  LOCAL FRM:=POSN+1;
  RETURN IFTE((POSN==0 OR FRM>SIZE(LST)),{},LST({FRM,SIZE(LST)}));
 END;

 EXPORT ListANDBOOL(LST,LSTBOOL,NewValue)
 //Replace items ANDed out with NULL(NewValue)
 //EG ({"AA","BB"},{0,1},"CHAR(0)") = {"","BB"}//Note the quotes
 //EG ({11,13},{0,1},"12")//NOMORETHAN12
 //RequirementSpec:
 //http://www.hpmuseum.org/forum/thread-5092.html
 //Usage:
 //http://www.hpmuseum.org/forum/thread-5031.html
 //See also:MaskBOOL
 //NULL=NULL
 BEGIN
  //Guard against empty "" giving syn err
  LOCAL MYNULL:=IFTE(NewValue=="","CHAR(0)",NewValue);
  IF SIZE(LST) AND SIZE(LSTBOOL) THEN
   RETURN EXECON("IFTE(&2,&1,"+MYNULL+")",LST,LSTBOOL);
  END;
  RETURN {};
 END;

 EXPORT ListAPPEND(LST,ITEM)
 //APPEND ITEM TO LIST
 //EG L2:=APPEND(L2,3)
 //PPL:L2(0):=3;
 //Py:APPEND(L2,3)
 //NULL: {ITEM}
 // (LST,{ITEMLST}) ADDS 1 ITEM (A LST)
 BEGIN
  RETURN LST(0):=ITEM; 
 END;

 EXPORT ListBEFORE(LST,POSN)
 //Slice Before POSN: 
 //POSN=0: ({1,2},0)={1}
 BEGIN
  LOCAL TOO:=POSN-1;
  IF POSN==0 THEN
    RETURN ListBEFORE(LST,SIZE(LST));
  END;
  RETURN IFTE(TOO>0,LST({1,TOO}),{});
 END;

 EXPORT ListCONCAT(LST1,LST2)
 //CONCATENATE
 BEGIN
  CONCAT(LST1,LST2);
 END;

 EXPORT ListCOUNT (LST,ITEM)
 //COUNT 1 ITEM:FASTEST
  //INTERSECT IS CURRENTLY QUICKER
  //BUT RECHECK AFTER ITERATIVE SOLN IMPL
 BEGIN
  RETURN ListCOUNTITEMS(LST,{ITEM});
 END;

 EXPORT ListCOUNTANYDUPLICATES(LST)
 //Current Implementation yields a sorted LST
 //But might change
 BEGIN
  ListANS:=ListSORT(LST);
  RETURN ListCOUNTANYDUPLICATES_SORTED(ListANS);
 END;

 EXPORT ListCOUNTANYDUPLICATES_SORTED(SortedLST)
 //Count how many duplicates in a sortedlist,Return a REAL INT
 //({1,9,9}=1 dup, {1,2,2,3,3,3}=3 dup)
 BEGIN
  LOCAL II;
  LOCAL DUPCOUNT:=0;
  IF SIZE(SortedLST)>1 THEN
   FOR II FROM 1 TO SIZE(SortedLST)-1 DO
    IF SortedLST(II) ==SortedLST(II+1) THEN
     DUPCOUNT:=DUPCOUNT+1;
    END;//IF
   END;//FOR
   //ELSE:SMALL LISTS HAVE NO DUPLICATES
  END;//IF
  RETURN DUPCOUNT;
 END;

 
 EXPORT ListCOUNTITEM(LST,ITEM)
 //Count Instances of 1 ITEM in LST
 //ITEM MAY BE A LIST COMPRISING 1 ITEM 
 //(USE COUNTITEMS TO SEARCH FOR A LIST OF ITEMS)
 //NULL LST:0
 //NULL ITEM:COUNTED
 
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  CASE
   IF POSN==0 THEN RETURN 0; END;
   //IF POSN==SIZE(LST)  THEN RETURN 1; END;
   DEFAULT
    //FOR LISTS WIH MANY DUPLICATES:
    //AN ITERATIVE SOLN WILL BE NEEDED
    RETURN 1+ListCOUNT(ListAFTER(LST,POSN),ITEM);
  END; 
 END;

 EXPORT ListCOUNTITEMS(LST,ITEMS)
 //ITEMS MAY BE 1 ITEM OR A LIST OF SEPARATE ITEMS
 //SO TO COUNT LISTS, CONTAIN THEM IN A LIST
 //EG {1,{},2},{{}}= 1
 //EG {1,2,3},{2,3} = 2
 //EG {1,{2,3}},{2,3} = 0 (TO SEARCH FOR ITEM {2,3} USE COUNT)
 //ITEMS NULL=0
 //THIS VERSION IS QUICKER,BUT PARAMETERS DIFFER
 BEGIN
  RETURN SIZE(INTERSECT(LST,ITEMS));
 END;
 
 EXPORT ListFIND(LST,ITEM)
  //See http://www.hpmuseum.org/forum/thread-9431.html
 BEGIN 
  LOCAL X,Y;
  LOCAL LSTPOSNS={};

  WHILE X:=POS(LST,ITEM) DO
    LSTPOSNS(0):=(Y:=X+Y);
    LST:=LST({X,SIZE(LST)}+1)
  END;
  RETURN LSTPOSNS;
 END;
 
 EXPORT ListGETLIST(LST,GETLST)
 //Solves Puzzle #32. POSN≥0.
 //POSN>SIZE(LST):EXCEPTION. RETURN {} FOR THAT ITEM
 BEGIN
 LOCAL II;

  IF SIZE(GETLST) THEN
   IF MAX(GETLST)>SIZE(LST) THEN
    RAISE(IndexOutOfBoundsException,"ListGETLIST",1);
   END;
   //IFTE GUARDS INDEX>SIZE(LST)
   RETURN MAKELIST(IFTE(GETLST(II)>SIZE(LST),{},LST(GETLST(II))),II,1,SIZE(GETLST));
  END;
  RETURN {};//ASKED TO GET NOTHING
 END;

 EXPORT ListHEAD(LST)
 //List HEAD AKA LISP CAR
 //NULL:ERR
 BEGIN
  IF SIZE(LST) THEN
   RETURN LST(1);
  END;
  RAISE(ListIsEmptyError,"HEAD",1);
  RETURN {};
 END;

 EXPORT ListINDEX(LST,ITEM)
 //Despite the confusing name
 //Simple: Return posn of 1st instance of item
 //NULL: 0
 BEGIN
  RETURN POS(LST,ITEM);
 END;

 EXPORT ListINSERT(LST,POSN,ITEM)
 //INSERT ITEM BEFORE POSN
 //PPL POSN=0 = APPEND
 //Py  POSN=0 = 1ST
 BEGIN
  LOCAL POSNB:=POSN-1;
  LOCAL LSTB:=IFTE(POSN==1,{},LST({1,POSNB}));
  LOCAL LSTA:=LST({POSN,SIZE(LST)});

  IF POSN==0 THEN //IN PPL:
   //IT IS UNCLEAR WHETHER THIS SHOULD APPEND,
   //OR INSERT BEFORE LAST 
   //OPINIONS?
   TBD();
   RETURN CONCAT(LST,ITEM);
  END;
  RETURN CONCAT(CONCAT(LSTB,ITEM),LSTA);
 END;

 EXPORT ListIsLIST(LST)
 //BOOL:Is parameter a list
 //In PPL lists and sets both 1
 BEGIN
   RETURN (TYPE(LST)==ListTYPE);
 END;

 EXPORT ListIsSET(LST)
 //BOOL:Is LST currently a set (no duplicates)
 //A uniquelist (no duplicates) may be a set
 //NULL:1
 BEGIN
  RETURN NOT(ListCOUNTANYDUPLICATES(LST));
 END;

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

 EXPORT ListMASKBOOL(LST,LSTBOOL,NewValue)
 //Mask selected values
 //Cf ANDBOOL
 //Here 1 selects replace, not 0
 //NULL=NULL
 BEGIN 
  //Guard against empty "" giving syn err
  LOCAL MYNULL:=IFTE(NewValue=="","CHAR(0)",NewValue);
  IF SIZE(LST) AND SIZE(LSTBOOL) THEN
   RETURN EXECON("IFTE(&2,"+MYNULL+",&1)",LST,LSTBOOL);
  END;
  RETURN {};
  //Equivalent to
  //RETURN ListANDBOOL(LST,NOT(LSTBOOL),NewValue);
 END;

 EXPORT ListMEAN(LST)
 BEGIN
  IF SIZE(LST) THEN
   RETURN mean(LST);
  END;
  RAISE(ListIsEmptyError,"ListMEAN",1);
  RETURN {};
 END;

 EXPORT ListMEAN2(LSTV,LSTF)
 BEGIN
  IF SIZE(LSTV) AND SIZE(LSTF) THEN
   RETURN mean(LSTV,LSTF);
  END;
  RAISE(ListIsEmptyError,"ListMEAN2",1);
  RETURN {};
 END;

 EXPORT ListMEDIAN(LST)
 BEGIN
  IF SIZE(LST) THEN
   RETURN(median(LST));
  END;
  RAISE(ListIsEmptyError,"ListMEDIAN",1);//(NO MEDIAN)
  RETURN {};///
 END;

 EXPORT ListMEDIAN2(LSTV,LSTF)
 BEGIN
  IF SIZE(LSTV) AND SIZE(LSTF) THEN
   RETURN(median(LSTV,LSTF));
  END;
  RAISE(ListIsEmptyError,"ListMEDIAN2",1);
  RETURN {};///
 END;

 EXPORT ListMODE2(LSTV,LSTF)
 //Get MODES of ItemXFrequency Lists
 //Empty=Empty
 BEGIN
  LOCAL II;
  LOCAL MODESLST:={};
  LOCAL MODEPOSNS:={};

  IF SIZE(LSTF) AND SIZE(LSTV) THEN
   //Find MODES
   MODEPOSNS:=ListFIND(LSTF,MAX(LSTF));
  
   FOR II FROM 1 TO SIZE(MODEPOSNS) DO
    MODESLST(II):=LSTV(MODEPOSNS(II));
   END;//FOR
  END;//IF
  RETURN MODESLST;
 END;
 //A FASTER IMPLEMENTATION OF MODE IS AT
 //http://www.hpmuseum.org/forum/thread-9393.html
 EXPORT ListMODE(LST)
 //Get MODES of LST : Empty = Empty
 BEGIN
  //Make uniquelst and count
  ListANS:=ListOCCURRENCES(LST);
  
  RETURN ListMODE2(ListANS(1),ListANS(2));
 END;

 EXPORT ListOCCURRENCES(LST)
 //Given a list
 //Return unique list of occurrences and their occurrence counts as 2 lists
 BEGIN
  LOCAL II;
  LOCAL LSTF:={};
  LOCAL LSTV:=ListREMOVEDUPLICATES(LST);

  FOR II FROM 1 TO SIZE(LSTV) DO
   LSTF(II):=ListCOUNT(LST,LSTV(II));
  END;
  RETURN {LSTV,LSTF};
 END;
//There must be a better name
 EXPORT ListInvOCCUR(LSTV,LSTF)
 //INVERSE OF OCCURRENCES
 //Given V and F yield V,F times
 //NULL=NULL
 //In an OCCURRENCES list V is unique and F>0
 //But We handle V with F=0 and V nonunique
 BEGIN
  LOCAL II,JJ;
  LOCAL LST:={};

  FOR II FROM 1 TO SIZE(LSTV) DO
   IF LSTF(II) THEN //V WITH F>0
    LST:=CONCAT(LST,MAKELIST(LSTV(II),JJ,1,LSTF(II)));
   END;
  END;
 
  RETURN LST;
 END;

 EXPORT ListPOP(LST,POSN)
 //POP POSN OFF LIST
 BEGIN
  LOCAL ITEM;
  IF SIZE(LST) THEN
   ITEM:=LST(IFTE(POSN,POSN,SIZE(LST)));//0=>LAST
   ListANS:=ListREMOVEX(LST,POSN);
  ELSE
   RAISE(ListIsEmptyError,"ListPOP",1);
   ITEM:={};
   ListANS:={};
  END;   
  //RETURN POPPED ITEM
  //BUT ALSO SAVE SHORTENED LST
  RETURN ITEM;
 END;

 EXPORT ListPOPLAST(LST)
 //POP POSN OFF LIST
 //Py: POP()
 BEGIN
  RETURN ListPOP(LST,SIZE(LST)); 
 END;

 EXPORT ListremoveX(LST,POSN)
 // CAS ALTERNATIVE TO REMOVEX:MAY BE SLOW
 //See 
 //http://www.hpmuseum.org/forum/thread-9406.html and
 //http://www.hpmuseum.org/forum/thread-7987.html?highlight=suppress 
 //NULL=NULL,POSN>SZE=LST
 BEGIN
  IF POSN THEN
   RETURN suppress(LST,POSN);
  END;
  RETURN suppress(LST,SIZE(LST));//0=LAST
 END;

 EXPORT ListREMOVEX(LST,POSN)
 //REMOVE 1 ITEM AT POSN
 //NULL=NULL,POSN>SIZE=LST (NOWT REMOVED)
 BEGIN
  LOCAL LSTB,LSTA;

  IF POSN THEN
   LSTB:=ListBEFORE(LST,POSN);
   LSTA:=ListAFTER (LST,POSN);
   RETURN CONCAT(LSTB,LSTA);
  ELSE
   //PPL: 0=Remove Last Item
   RETURN ListREMOVEX(LST,SIZE(LST));
   //Py: 0=RemoveFirst ie return TAIL
  END;
 END;
 
 EXPORT Listremove(LST,ITEM) 
 //CAS version slower
 //NULL=NULL
 BEGIN
  RETURN remove(ITEM,LST);
 END;

 EXPORT ListREMOVE(LST,ITEM)
 //Remove 1 instance of ITEM
 //NULL=NULL 
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  IF POSN THEN
   RETURN ListREMOVEX(LST,POSN);
  END;
  RAISE(ItemNotFoundError,ITEM,0);
  RETURN LST;//NOTHING TO REMOVE
 END;

 EXPORT ListREMOVEDUPLICATES(LST)
 //RESULT WITH DUPLICATES JUST ONCE 
 //Native: Sequence NOT determined but seems same
 //From #21
 BEGIN
  RETURN UNION(LST);
 END;

 EXPORT ListREMOVEDUPLICATESSL(LST)
 //SL
 //My own implementation ensures known list sequence (per original LST)
 BEGIN
  LOCAL II;
  LOCAL ListANS:={};

  FOR II FROM 1 TO SIZE(LST)  DO
   IF POS(ListANS,LST(II))==0 THEN //NOT YET LISTED
    ListANS(0):=LST(II);//ADD ENTRY
   END;
  END;
  RETURN ListANS;//EACH ITEM ONCE
 END;

 EXPORT ListREPLACE(LST,ITEM,ITEM2)
 //Replace instances of ITEM with ITEM2
 BEGIN
  LOCAL II;
  LOCAL FOUND:=ListFIND(LST,ITEM);
  IF SIZE(FOUND) THEN
   ListANS:=LST;
   FOR II FROM 1  TO SIZE(FOUND)  DO
    ListANS(FOUND(II)):=ITEM2;
   END;
  ELSE
   RETURN LST;
  END;
  RETURN ListANS; 
 END;

 EXPORT ListSLICE(LST,FRM,TOO)
 //RETURN PART OF LIST
 //SYNTAX HINT
 //SUGGEST ALSO IMPL (LST,{2,3})
 //FRM≤TOO:Bad Inputs={}
 BEGIN
  LOCAL TTOO:=IFTE(TOO==0,SIZE(LST),TOO); //TO 0==LAST
  LOCAL TFRM:=IFTE(FRM==0,SIZE(LST),FRM); //FRM 0==LAST
  //MSGBOX("SLICE "+{FRM,TOO});
  IF TFRM>TTOO THEN
    RAISE(IndexOutOfBoundsException,FRM,1);//Maybe a new error
    RETURN {};
  END; 
  RETURN LST({TFRM,TTOO});
 END;

 EXPORT ListSORT(LST)
 //This implementation uses native SORT
 //On old compilers See known bugs 
 //This will not affect MODE other than changing ordering 
 BEGIN
  RETURN SORT(LST);
 END;

 EXPORT ListTAIL(LST)
 //List TAIL AKA LISP CDR
 //NULL:ERR
 //(SOME USE TAIL=LAST NOT TAIL=CDR)
 BEGIN
  IF SIZE(LST) THEN
   RETURN LST({2,SIZE(LST)});
  END;
  RAISE(ListIsEmptyError,"TAIL",1);
  RETURN {};
 END;

 EXPORT ListToSET(LST)
 //In addition to making the list like a set
 //wibni we could track those tnat ARE sets
 BEGIN
  RETURN ListREMOVEDUPLICATES(LST);
 END;

 EXPORT ListVERSION()
 BEGIN
  RETURN CRID;
 END;

 // Python names(LC) prefixed Py ()
 // Py  syntax: Lst.append(ITEM) etc 
 // PPL syntax: Lst:=append(Lst,ITEM)
 // Py indexes from 0 but not yet implemented
 // These names are inspired by Py, 
 // but will never provide exact equivalents.
 
 EXPORT Pyappend(LST,ITEM)
 //append a single item
 BEGIN 
  RETURN append(LST,ITEM);//CAS
 END;

 EXPORT Pyclear(LST)
 //Py :ALSO DELETES LIST (cf CAS purge)
 BEGIN 
  RETURN {};
 END;

 EXPORT Pycopy(LST)
 //Py: A shallow copy PPL: simple copy
 BEGIN
  RETURN LST;
 END;

 EXPORT Pycount(LST,ITEM)
 //Py :Count occurences of item
 BEGIN
  RETURN ListCOUNT(LST,ITEM);
 END;

 EXPORT Pyextend(LST,LST2)
 //Py :Concat items in LST2 to LST
 //Query: If listfull, should we add some or none
 //PPL:LST2 may be an item 
 BEGIN
  CONCAT(LST,LST2);
 END;

 EXPORT Pyindex(LST,ITEM)
 //Py :Return index (or ValueErr)

 //TBD START:END LIMIT RANGE SEARCHED WITHOUT CHANGING INDEX
 BEGIN
  LOCAL LX:=ListINDEX(LST,ITEM); 
  IF LX==0 THEN
   RAISE(ValueError,ITEM,1);//Py:NotFound => an error
  END;
  RETURN LX; 
 END;

 EXPORT Pyinsert(LST,POSN,ITEM)
 //Py :Insert ITEM before POS
 BEGIN
  IF POSN==0 THEN
   TBD();
   CONCAT(ITEM,LST);//Py 0
  END;
  RETURN ListINSERT(LST,POSN,ITEM); 
 END;

 EXPORT Pypop(LST,POSN)
 //Py :Pop item (Posn Omit:Last)
 //PPL:Posn reqd
 BEGIN
  IF POSN==0 THEN
   TBD();
  END;
  RETURN ListPOP(LST,POSN);
 END;

 EXPORT PypopLast(LST)
 //Py :Pop item (Posn Omit:Last)
 //PPL:Twofunctions
 BEGIN
  RETURN ListPOPLAST(LST);
 END;

 EXPORT Pyremove(LST,ITEM)
 //Py :Remove 1st ITEM,ERR IF NONE
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  IF POSN THEN
   RETURN ListREMOVEX(LST,POSN);
  END;
  //ELSE NOTHING TO REMOVE
  RAISE(ItemNotFoundError,ITEM,1);
  RETURN LST;
 END;
 
 EXPORT Pyreverse (LST)
 BEGIN
  RETURN REVERSE(LST);
 END;

 EXPORT Pysort(LST,KeyFunc,RReverse)
 //TBD: KeyFunc: Selects sort key from itapprox()
 BEGIN
  IF TYPE(KeyFunc)==NumTYPE AND KeyFunc==0 THEN
   //0=None=NO FUNC
  ELSE
   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,3);//40
  LST(2):="21. ListREMOVEDUPLICATES";
  LST(3):="32. ListGETLIST";
  CHOOSE(VR,"Puzzles",LST);
 END;

 EXPORT ListPythonAnalogues ()
 BEGIN
  LOCAL KK;
  LOCAL PyFuns:={"Pyappend",
   "Pyclear","Pycopy","Pycount",
   "Pyextend",
   "Pyindex","Pyinsert",
   "Pypop","Pypoplast",
   "Pyremove","Pyreverse",
   "Pysort"};
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,"Py analogues",PyFuns)

 END;

 EXPORT ListStatisticalFunctions()
 BEGIN
  LOCAL KK;
  //Just listed to group these Not choosable
  CHOOSE(KK,"Statistical Functions",
   {"ListMEAN","ListMEAN2",
    "ListMEDIAN","ListMEDIAN2",
    "ListMODE","ListMODE2"});
 END;

 
 EXPORT ListExamples()
 //In real use, use XXX:=List...()
 BEGIN
  LOCAL LL:={1,2,3,4,5,6,7,8,9};
  PRINT();
  PRINT(ListVERSION);
  //PRINT("A");
  PRINT(ListAFTER(LL,2));
  PRINT(ListANDBOOL({1,12},{0,1},"122"));
  PRINT(ListANDBOOL({"AA","BB"},{0,1},"CHAR(0)"));
  PRINT(ListBEFORE(LL,2));
  //PRINT("C");
  PRINT(ListCOUNT({},2));
  PRINT(ListCOUNTANYDUPLICATES_SORTED({}));
  PRINT(ListCOUNTANYDUPLICATES({0,2,2,2}));
  //PRINT("F");
  PRINT(ListFIND(LL,2));
  PRINT(ListHEAD(LL));
  PRINT(ListINDEX(LL,2));
  PRINT(ListINSERT(LL,2,4));
  PRINT(ListIsLIST(5));
  PRINT(ListIsSET(LL));
  PRINT(ListIsSORTED(LL)); 
  PRINT(ListMASKBOOL({1,12},{0,1},"122"));
  PRINT(ListMASKBOOL({"AA","BB"},{0,1},"CHAR(0)"));
  PRINT(ListOCCURRENCES(LL));
  PRINT(ListPOP(LL,2));LL:=ListANS;
  PRINT(ListPOPLAST(LL));LL:=ListANS;
  PRINT(ListREMOVEX(LL,2));
  PRINT(ListREMOVE(LL,9));
  PRINT(ListSLICE({1,2,3,4},2,3));
  PRINT(ListSORT(LL));
  PRINT(ListTAIL(LL));
  PRINT(ListToSET({1,2,2}));
 
  PRINT(ListMEAN(LL));
  PRINT(ListMEDIAN(LL));
  PRINT(ListMODES({"AC","DC"})); 
 
  PRINT("Exampled");
  //RETURN ListCOUNT({1,2,2,2},2);
 END;

 EXPORT LIST()
 BEGIN
  ABOUT();
  //ListExamples();
 END;

Stephen Lewkowicz (G1CMZ)
Visit this user's website Find all posts by this user
Quote this message in a reply
11-09-2017, 11:40 PM
Post: #3
RE: List API (G1CMZ): List Processing API
Version 1.0

Code:


 LOCAL CRID:="List API V1.0 © 2017 StephenG1CMZ";

 //Customise
 EXPORT ListShowErrors:=1;//SHOW ERRORS
 EXPORT ListNumericTypes:={DOM_FLOAT-1,DOM_INT-1,DOM_COMPLEX-1,DOM_MATRIX-1};
 //Query: Include COMPLEX,LONGFLOAT,MATRIX?
 //End

 //Forward
 ListCOUNTITEM(LST,ITEM);
 ListCOUNTITEMS(LST,ITEMS);
 ListIsTYPE(LST,TYPES);
 ListREMOVEDUPLICATES(LST);
 ListREMOVEX(LST,POSN);
 ListSORT(LST);

 //NB In main routines (ie not Python)
 //POSN parameter is >=0 (0=LAST)
 //POSN returned is ≥0 (PPL,0=NOTIN)

 //LOCAL SL:=1;
 LOCAL NL:="\n";
 LOCAL EMPTY0:=0;//ADDITIVE
 LOCAL EMPTY1:=1;//MULTIPLICATIVE

//TO REFER TO ListTYPE, USE DOM_LIST-1; MAGIC NUMBER FOR LISTS.

 LOCAL ListANS;//OUTPUT LIST(WHEN NOT RETURNED)
  //Also, useful temporary results 

 //ERR 
 LOCAL NaN:="NaN";
 LOCAL ListErrK:=1;
 LOCAL PyErrK:=3;
 EXPORT ListLastError:=0;
 LOCAL ERRKIND:={"","Error","","Py Error"};
 LOCAL ERRLST:={
  "IndexOutofBoundsException",
  "ListIsEmptyError",
  "ListIsFullError",
  "ListStatisticsError",
  "ItemNotFoundError",
  "ValueError"
 };
 //ERRNO IS ARBITRARY:INDEXES ERRLST
 LOCAL IndexOutOfBoundsException:=1;//List J
 LOCAL ListIsEmptyError:=2;
 LOCAL ListIsFullError:=3;//UNUSED YET
 LOCAL ListStatisticsError:=4;//UNUSED
 LOCAL ItemNotFoundError:=5;//List Py
 LOCAL ValueError:=6; // Py
 
 EXPORT ABOUT()
 BEGIN
  MSGBOX(CRID);
 END;

 TBD()
 BEGIN
  MSGBOX( "List: TBD");
 END;
 
 EXPORT RAISE(ERR,CULPRIT,SEVERITY)
 //Only exported for testing
 BEGIN
  IF ListShowErrors AND SEVERITY>0 THEN
   MSGBOX("List: "+ERRKIND(SEVERITY+1)+NL+ERRLST(ERR)+NL+CULPRIT);
  END;
  ListLastError:=ERR;
 END;

 NAN()
 BEGIN
  RETURN NaN;
 END;

 //MAINLY STANDARD FUNCTIONS

 EXPORT ListΣLIST(LST)
 BEGIN
  RETURN IFTE(SIZE(LST),ΣLIST(LST),EMPTY0); 
 END;

 EXPORT ListΠLIST(LST)
 BEGIN
  LOCAL SZ:=SIZE(LST);
  
  IF SZ>1 THEN RETURN ΠLIST(LST);
  END;
  IF SZ==1 THEN RETURN LST(1);
  END;
  //IF SZ==0 THEN
  RETURN EMPTY1;
  //END;
 END;

 EXPORT ListAFTER(LST,POSN)
 //Slice After POSN:
 //POSN=0 OR LAST:{}
 BEGIN
  LOCAL FRM:=POSN+1;
  RETURN IFTE((POSN==0 OR FRM>SIZE(LST)),{},LST({FRM,SIZE(LST)}));
 END;

 EXPORT ListANDBOOL(LST,LSTBOOL,NewValue)
 //Replace items ANDed out with NULL(NewValue)
 //EG ({"AA","BB"},{0,1},"CHAR(0)") = {"","BB"}//Note the quotes
 //EG ({11,13},{0,1},"12")//NOMORETHAN12
 //RequirementSpec:
 //http://www.hpmuseum.org/forum/thread-5092.html
 //Usage:
 //http://www.hpmuseum.org/forum/thread-5031.html
 //See also:MaskBOOL
 //NULL=NULL
 BEGIN
  //Guard against empty "" giving syn err
  LOCAL MYNULL:=IFTE(NewValue=="","CHAR(0)",NewValue);
  IF SIZE(LST) AND SIZE(LSTBOOL) THEN
   RETURN EXECON("IFTE(&2,&1,"+MYNULL+")",LST,LSTBOOL);
  END;
  RETURN {};
 END;

 EXPORT ListAPPEND(LST,ITEM)
 //APPEND ITEM TO LIST
 //EG L2:=APPEND(L2,3)
 //PPL:L2(0):=3;
 //Py:APPEND(L2,3)
 //NULL: {ITEM}
 // (LST,{ITEMLST}) ADDS 1 ITEM (A LST)
 BEGIN
  RETURN LST(0):=ITEM; 
 END;

 EXPORT ListBEFORE(LST,POSN)
 //Slice Before POSN: 
 //POSN=0: ({1,2},0)={1}
 BEGIN
  LOCAL TOO:=POSN-1;
  IF POSN==0 THEN
    RETURN ListBEFORE(LST,SIZE(LST));
  END;
  RETURN IFTE(TOO>0,LST({1,TOO}),{});
 END;

 EXPORT ListCONCAT(LST1,LST2)
 //CONCATENATE
 BEGIN
  CONCAT(LST1,LST2);
 END;

 EXPORT ListCOUNT (LST,ITEM)
 //COUNT 1 ITEM:FASTEST
  //INTERSECT IS CURRENTLY QUICKER
  //BUT RECHECK AFTER ITERATIVE SOLN IMPL
 BEGIN
  RETURN ListCOUNTITEMS(LST,{ITEM});
 END;

 EXPORT ListCOUNTANYDUPLICATES(LST)
 //Current Implementation yields a sorted LST
 //But might change
 BEGIN
  ListANS:=ListSORT(LST);
  RETURN ListCOUNTANYDUPLICATES_SORTED(ListANS);
 END;

 EXPORT ListCOUNTANYDUPLICATES_SORTED(SortedLST)
 //Count how many duplicates in a sortedlist,Return a REAL INT
 //({1,9,9}=1 dup, {1,2,2,3,3,3}=3 dup)
 BEGIN
  LOCAL II;
  LOCAL DUPCOUNT:=0;
  IF SIZE(SortedLST)>1 THEN
   FOR II FROM 1 TO SIZE(SortedLST)-1 DO
    IF SortedLST(II) ==SortedLST(II+1) THEN
     DUPCOUNT:=DUPCOUNT+1;
    END;//IF
   END;//FOR
   //ELSE:SMALL LISTS HAVE NO DUPLICATES
  END;//IF
  RETURN DUPCOUNT;
 END;
 
 EXPORT ListCOUNTITEM(LST,ITEM)
 //Count Instances of 1 ITEM in LST
 //ITEM MAY BE A LIST COMPRISING 1 ITEM 
 //(USE COUNTITEMS TO SEARCH FOR A LIST OF ITEMS)
 //NULL LST:0
 //NULL ITEM:COUNTED
 
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  CASE
   IF POSN==0 THEN RETURN 0; END;
   //IF POSN==SIZE(LST)  THEN RETURN 1; END;
   DEFAULT
    //FOR LISTS WIH MANY DUPLICATES:
    //AN ITERATIVE SOLN WILL BE NEEDED
    RETURN 1+ListCOUNT(ListAFTER(LST,POSN),ITEM);
  END; 
 END;

 EXPORT ListCOUNTITEMS(LST,ITEMS)
 //ITEMS MAY BE 1 ITEM OR A LIST OF SEPARATE ITEMS
 //SO TO COUNT LISTS, CONTAIN THEM IN A LIST
 //EG {1,{},2},{{}}= 1
 //EG {1,2,3},{2,3} = 2
 //EG {1,{2,3}},{2,3} = 0 (TO SEARCH FOR ITEM {2,3} USE COUNT)
 //ITEMS NULL=0
 //THIS VERSION IS QUICKER,BUT PARAMETERS DIFFER
 BEGIN
  RETURN SIZE(INTERSECT(LST,ITEMS));
 END;
 
 EXPORT ListDIFFER2(LST1,LST2)
 //POSITION OF 1st DIFFERENCE
 //FLOAT≠INTEGER
 //SIZE≠SIZE: SZ+1 RETURNED(UNLESS EARLIER DIFFERENCE)
 BEGIN
  LOCAL II:=1;
  LOCAL SZ:=MIN(SIZE(LST1),SIZE(LST2));

  IF EQ(LST1,LST2) THEN
   RETURN 0;
  END;
  //IF SIZE(LST1)≠SIZE(LST2) THEN
  // RETURN −1;
  //END;
  WHILE II≤SZ DO
   IF TYPE(LST1)≠TYPE(LST2) OR LST1(II)≠LST2(II) THEN
    RETURN II;
   END;
   II:=II+1;
  END; 
  RETURN IFTE(SIZE(LST1)>SZ OR SIZE(LST2)>SZ,SZ+1,0);
 END;

 EXPORT ListFIND(LST,ITEM)
  //See http://www.hpmuseum.org/forum/thread-9431.html
 BEGIN 
  LOCAL X,Y;
  LOCAL LSTPOSNS={};

  WHILE X:=POS(LST,ITEM) DO
    LSTPOSNS(0):=(Y:=X+Y);
    LST:=LST({X,SIZE(LST)}+1)
  END;
  RETURN LSTPOSNS;
 END;
 
 EXPORT ListGETLIST(LST,GETLST)
 //Solves Puzzle #32. POSN≥0.
 //POSN>SIZE(LST):EXCEPTION. RETURN {} FOR THAT ITEM
 BEGIN
 LOCAL II;

  IF SIZE(GETLST) THEN
   IF MAX(GETLST)>SIZE(LST) THEN
    RAISE(IndexOutOfBoundsException,"ListGETLIST",ListErrK);
   END;
   //IFTE GUARDS INDEX>SIZE(LST)
   RETURN MAKELIST(IFTE(GETLST(II)>SIZE(LST),{},LST(GETLST(II))),II,1,SIZE(GETLST));
  END;
  RETURN {};//ASKED TO GET NOTHING
 END;

 EXPORT ListHEAD(LST)
 //List HEAD AKA LISP CAR
 //NULL:ERR
 BEGIN
  IF SIZE(LST) THEN
   RETURN LST(1);
  END;
  RAISE(ListIsEmptyError,"HEAD",ListErrK);
  RETURN {};
 END;

 EXPORT ListINDEX(LST,ITEM)
 //Despite the confusing name
 //Simple: Return posn of 1st instance of item
 //NULL: 0
 BEGIN
  RETURN POS(LST,ITEM);
 END;

 EXPORT ListINSERT(LST,POSN,ITEM)
 //INSERT ITEM BEFORE POSN
 //PPL POSN=0 = APPEND
 //Py  POSN=0 = 1ST
 BEGIN
  LOCAL POSNB:=POSN-1;
  LOCAL LSTB:=IFTE(POSN==1,{},LST({1,POSNB}));
  LOCAL LSTA:=LST({POSN,SIZE(LST)});

  IF POSN==0 THEN //IN PPL:
   //IT IS UNCLEAR WHETHER THIS SHOULD APPEND,
   //OR INSERT BEFORE LAST 
   //OPINIONS?
   //TBD();
   RETURN CONCAT(LST,ITEM);
  END;
  RETURN CONCAT(CONCAT(LSTB,ITEM),LSTA);
 END;

 //Query:
 //IsLIST,IsSET ask-Is parameter this
 //IsNUMERIC,IsTYPE ask:Are contents this
 //Change names to clarify?

 EXPORT ListIsLIST(LST)
 //BOOL:Is entire parameter a list
 //In PPL lists and sets both 1
 BEGIN
   RETURN (TYPE(LST)==ListTYPE);
 END;

 EXPORT ListIsNUMERIC(LST)
 //Is list currently numeric
 BEGIN 
  RETURN ListIsTYPE(LST,ListNumericTypes);
 END;

 EXPORT ListIsSET(LST)
 //BOOL:Is LST currently a set (no duplicates)
 //A uniquelist (no duplicates) may be a set
 //NULL:1
 BEGIN
  RETURN NOT(ListCOUNTANYDUPLICATES(LST));
 END;

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

 EXPORT ListIsTYPE(LST,TYPES)
 //TYPES: TYPE OR LIST OF TYPES
 //SEE ALSO:IsNUMERIC
 //MAKELIST IS FASTER THAN [FOR,INCREMENT COUNT] 
 BEGIN
  LOCAL II;

  IF TYPE(TYPES)==DOM_FLOAT-1 THEN RETURN IsTYPE(LST,{TYPES});
  END;
 
  IF SIZE(LST) AND SIZE(TYPES) THEN
   ListANS:=MAKELIST(IFTE(POS(TYPES,TYPE(LST(II))),1,0),II,1,SIZE(LST));//List matching types
   RETURN IFTE(ΣLIST(ListANS)==SIZE(LST),1,0); //Count them
  END;
  RAISE(ListIsEmptyError,"ListIsTYPE",1);
  //EMPTY LST: LST ALWAYS INDETERMINATE (GUARD) 
  //EMPTY TYPES: 0>NO MATCHES OR 1>NO REJECTS 
  RETURN 0;//INDETERMINATE
 END;

 EXPORT ListMASKBOOL(LST,LSTBOOL,NewValue)
 //Mask selected values
 //Cf ANDBOOL
 //Here 1 selects replace, not 0
 //NULL=NULL
 BEGIN 
  //Guard against empty "" giving syn err
  LOCAL MYNULL:=IFTE(NewValue=="","CHAR(0)",NewValue);
  IF SIZE(LST) AND SIZE(LSTBOOL) THEN
   RETURN EXECON("IFTE(&2,"+MYNULL+",&1)",LST,LSTBOOL);
  END;
  RETURN {};
  //Equivalent to
  //RETURN ListANDBOOL(LST,NOT(LSTBOOL),NewValue);
 END;

EXPORT ListMAX(LST)
BEGIN
  RETURN IFTE(SIZE(LST),MAX(LST),EMPTY0);
END;

 EXPORT ListMEAN(LST)
 BEGIN
  IF SIZE(LST) THEN
   RETURN mean(LST);
  END;
  RAISE(ListIsEmptyError,"ListMEAN",ListErrK);
  RETURN NAN();
 END;

 EXPORT ListMEAN2(LSTV,LSTF)
 BEGIN
  IF SIZE(LSTV) AND SIZE(LSTF) THEN
   RETURN mean(LSTV,LSTF);
  END;
  RAISE(ListIsEmptyError,"ListMEAN2",ListErrK);
  RETURN NAN();
 END;

 EXPORT ListMEDIAN(LST)
 BEGIN
  IF SIZE(LST) THEN
   RETURN(median(LST));
  END;
  RAISE(ListIsEmptyError,"ListMEDIAN",ListErrK);//(NO MEDIAN)
  RETURN NAN();///
 END;

 EXPORT ListMEDIAN2(LSTV,LSTF)
 BEGIN
  IF SIZE(LSTV) AND SIZE(LSTF) THEN
   RETURN(median(LSTV,LSTF));
  END;
  RAISE(ListIsEmptyError,"ListMEDIAN2",ListErrK);
  RETURN NAN();///
 END;

 EXPORT ListMIN(LST)
 BEGIN
  RETURN IFTE(SIZE(LST),MIN(LST),EMPTY0);
 END;

 EXPORT ListMODE2(LSTV,LSTF)
 //Get MODES of ItemXFrequency Lists
 //Empty=Empty
 BEGIN
  LOCAL II;
  LOCAL MODESLST:={};
  LOCAL MODEPOSNS:={};

  IF SIZE(LSTF) AND SIZE(LSTV) THEN
   //Find MODES
   MODEPOSNS:=ListFIND(LSTF,MAX(LSTF));
  
   FOR II FROM 1 TO SIZE(MODEPOSNS) DO
    MODESLST(II):=LSTV(MODEPOSNS(II));
   END;//FOR
  END;//IF
  RETURN MODESLST;
 END;
 //A FASTER IMPLEMENTATION OF MODE IS AT
 //http://www.hpmuseum.org/forum/thread-9393.html
 EXPORT ListMODE(LST)
 //Get MODES of LST : Empty = Empty
 BEGIN
  //Make uniquelst and count
  ListANS:=ListOCCURRENCES(LST);
  
  RETURN ListMODE2(ListANS(1),ListANS(2));
 END;

 EXPORT ListOCCURRENCES(LST)
 //Given a list
 //Return unique list of occurrences and their occurrence counts as 2 lists
 BEGIN
  LOCAL II;
  LOCAL LSTF:={};
  LOCAL LSTV:=ListREMOVEDUPLICATES(LST);

  FOR II FROM 1 TO SIZE(LSTV) DO
   LSTF(II):=ListCOUNT(LST,LSTV(II));
  END;
  RETURN {LSTV,LSTF};
 END;
//There must be a better name
 EXPORT ListInvOCCUR(LSTV,LSTF)
 //INVERSE OF OCCURRENCES
 //Given V and F yield V,F times
 //NULL=NULL
 //In an OCCURRENCES list V is unique and F>0
 //But We handle V with F=0 and V nonunique
 BEGIN
  LOCAL II,JJ;
  LOCAL LST:={};

  FOR II FROM 1 TO SIZE(LSTV) DO
   IF LSTF(II) THEN //V WITH F>0
    LST:=CONCAT(LST,MAKELIST(LSTV(II),JJ,1,LSTF(II)));
   END;
  END;
 
  RETURN LST;
 END;

 EXPORT ListPOP(LST,POSN)
 //POP POSN OFF LIST
 BEGIN
  LOCAL ITEM;
  IF SIZE(LST) THEN
   ITEM:=LST(IFTE(POSN,POSN,SIZE(LST)));//0=>LAST
   ListANS:=ListREMOVEX(LST,POSN);
  ELSE
   RAISE(ListIsEmptyError,"ListPOP",ListErrK);
   ITEM:={};
   ListANS:={};
  END;   
  //RETURN POPPED ITEM
  //BUT ALSO SAVE SHORTENED LST
  RETURN ITEM;
 END;

 EXPORT ListPOPLAST(LST)
 //POP POSN OFF LIST
 //Py: POP()
 BEGIN
  RETURN ListPOP(LST,SIZE(LST)); 
 END;

 EXPORT ListremoveX(LST,POSN)
 // CAS ALTERNATIVE TO REMOVEX:MAY BE SLOW
 //See 
 //http://www.hpmuseum.org/forum/thread-9406.html and
 //http://www.hpmuseum.org/forum/thread-7987.html?highlight=suppress 
 //NULL=NULL,POSN>SZE=LST
 BEGIN
  IF POSN THEN
   RETURN suppress(LST,POSN);
  END;
  RETURN suppress(LST,SIZE(LST));//0=LAST
 END;

 EXPORT ListREMOVEX(LST,POSN)
 //REMOVE 1 ITEM AT POSN
 //NULL=NULL,POSN>SIZE=LST (NOWT REMOVED)
 BEGIN
  LOCAL LSTB,LSTA;

  IF POSN THEN
   LSTB:=ListBEFORE(LST,POSN);
   LSTA:=ListAFTER (LST,POSN);
   RETURN CONCAT(LSTB,LSTA);
  ELSE
   //PPL: 0=Remove Last Item
   RETURN ListREMOVEX(LST,SIZE(LST));
   //Py: 0=RemoveFirst ie return TAIL
  END;
 END;
 
 EXPORT Listremove(LST,ITEM) 
 //CAS version slower
 //NULL=NULL
 BEGIN
  RETURN remove(ITEM,LST);
 END;

 EXPORT ListREMOVE(LST,ITEM)
 //Remove 1 instance of ITEM
 //NULL=NULL 
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  IF POSN THEN
   RETURN ListREMOVEX(LST,POSN);
  END;
  RAISE(ItemNotFoundError,ITEM,0);
  RETURN LST;//NOTHING TO REMOVE
 END;

 EXPORT ListREMOVEDUPLICATES(LST)
 //RESULT WITH DUPLICATES JUST ONCE 
 //Native: Sequence NOT determined but seems same
 //From #21
 BEGIN
  RETURN UNION(LST);
 END;

 EXPORT ListREMOVEDUPLICATESSL(LST)
 //SL
 //My own implementation ensures known list sequence (per original LST)
 BEGIN
  LOCAL II;
  LOCAL ListANS:={};

  FOR II FROM 1 TO SIZE(LST)  DO
   IF POS(ListANS,LST(II))==0 THEN //NOT YET LISTED
    ListANS(0):=LST(II);//ADD ENTRY
   END;
  END;
  RETURN ListANS;//EACH ITEM ONCE
 END;

 EXPORT ListREMOVEITEM(LST,ITEM)
 //ALL INSTANCES.PUZZLE #40.
 BEGIN
  LOCAL II;
  LOCAL FOUND:=ListFIND(LST,ITEM);
  IF SIZE(FOUND) THEN
   ListANS:=LST;
   //Remove from right:earlier posns unchanged
   FOR II FROM SIZE(FOUND) DOWNTO 1 DO
    ListANS:=ListREMOVEX(ListANS,FOUND(II));
   END;
   RETURN ListANS;
  END;//IF
  RETURN LST;//NOTHING REMOVED 
 END;

 EXPORT ListREPLACE(LST,ITEM,ITEM2)
 //Replace instances of ITEM with ITEM2
 BEGIN
  LOCAL II;
  LOCAL FOUND:=ListFIND(LST,ITEM);
  IF SIZE(FOUND) THEN
   ListANS:=LST;
   FOR II FROM 1  TO SIZE(FOUND)  DO
    ListANS(FOUND(II)):=ITEM2;
   END;
  ELSE
   RETURN LST;
  END;
  RETURN ListANS; 
 END;

 EXPORT ListSHUFFLE(LST_NUM)
 //SHUFFLE NUM: SHUFFLE 1..N INDEXES 
 //SHUFFLE LST: SHUFFLE LST
 //N<0:GUARD:UNSHUFFLED INDEX
 //NULL OR 0 OR >10000: NULL 
 BEGIN
  LOCAL II,NUM;
  IF TYPE(LST_NUM)=DOM_FLOAT-1 THEN
   NUM:=IFTE(LST_NUM>10000,0,LST_NUM);
   IF LST_NUM<0 THEN //GUARD NEGATIVES (AVOID CRASH)
    RETURN MAKELIST(II,II,1,ABS(NUM));//UNSHUFFLED
   END;
  END;
  RETURN mat2list(randperm(LST_NUM));
 END;

 EXPORT ListSLICE(LST,FRM,TOO)
 //RETURN PART OF LIST
 //SYNTAX HINT
 //SUGGEST ALSO IMPL (LST,{2,3})
 //FRM≤TOO:Bad Inputs={}
 BEGIN
  LOCAL TTOO:=IFTE(TOO==0,SIZE(LST),TOO); //TO 0==LAST
  LOCAL TFRM:=IFTE(FRM==0,SIZE(LST),FRM); //FRM 0==LAST
  //MSGBOX("SLICE "+{FRM,TOO});
  IF TFRM>TTOO THEN
    RAISE(IndexOutOfBoundsException,FRM,ListErrK);//Maybe a new error
    RETURN {};
  END; 
  RETURN LST({TFRM,TTOO});
 END;

 EXPORT ListSORT(LST)
 //This implementation uses native SORT
 //On old compilers See known bugs 
 //This will not affect MODE other than changing ordering 
 BEGIN
  RETURN SORT(LST);
 END;

 EXPORT ListTAIL(LST)
 //List TAIL AKA LISP CDR
 //NULL:ERR
 //(SOME USE TAIL=LAST NOT TAIL=CDR)
 BEGIN
  IF SIZE(LST) THEN
   RETURN LST({2,SIZE(LST)});
  END;
  RAISE(ListIsEmptyError,"TAIL",ListErrK);
  RETURN {};
 END;

 EXPORT ListToSET(LST)
 //In addition to making the list like a set
 //wibni we could track those tnat ARE sets
 BEGIN
  RETURN ListREMOVEDUPLICATES(LST);
 END;

 EXPORT ListVERSION()
 BEGIN
  RETURN CRID;
 END;

 // Python names(LC) prefixed Py ()
 // Py  syntax: Lst.append(ITEM) etc 
 // PPL syntax: Lst:=append(Lst,ITEM)
 // Py indexes from 0 but not yet implemented
 // These names are inspired by Py, 
 // but will never provide exact equivalents.
 
 EXPORT Pyappend(LST,ITEM)
 //append a single item
 BEGIN 
  RETURN append(LST,ITEM);//CAS
 END;

 EXPORT Pyclear(LST)
 //Py :ALSO DELETES LIST (cf CAS purge)
 BEGIN 
  RETURN {};
 END;

 EXPORT Pycopy(LST)
 //Py: A shallow copy PPL: simple copy
 BEGIN
  RETURN LST;
 END;

 EXPORT Pycount(LST,ITEM)
 //Py :Count occurences of item
 BEGIN
  RETURN ListCOUNT(LST,ITEM);
 END;

 EXPORT Pyextend(LST,LST2)
 //Py :Concat items in LST2 to LST
 //Query: If listfull, should we add some or none
 //PPL:LST2 may be an item 
 BEGIN
  CONCAT(LST,LST2);
 END;

 EXPORT Pyindex(LST,ITEM)
 //Py :Return index (or ValueErr)

 //TBD START:END LIMIT RANGE SEARCHED WITHOUT CHANGING INDEX
 BEGIN
  LOCAL LX:=ListINDEX(LST,ITEM); 
  IF LX==0 THEN
   RAISE(ValueError,ITEM,PyErrK);//Py:NotFound => an error
  END;
  RETURN LX; 
 END;

 EXPORT Pyinsert(LST,POSN,ITEM)
 //Py :Insert ITEM before POS
 BEGIN
  IF POSN==0 THEN
   TBD();
   CONCAT(ITEM,LST);//Py 0
  END;
  RETURN ListINSERT(LST,POSN,ITEM); 
 END;

 EXPORT Pypop(LST,POSN)
 //Py :Pop item (Posn Omit:Last)
 //PPL:Posn reqd
 BEGIN
  IF POSN==0 THEN
   TBD();
  END;
  RETURN ListPOP(LST,POSN);
 END;

 EXPORT PypopLast(LST)
 //Py :Pop item (Posn Omit:Last)
 //PPL:Twofunctions
 BEGIN
  RETURN ListPOPLAST(LST);
 END;

 EXPORT Pyremove(LST,ITEM)
 //Py :Remove 1st ITEM,ERR IF NONE
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  IF POSN THEN
   RETURN ListREMOVEX(LST,POSN);
  END;
  //ELSE NOTHING TO REMOVE
  RAISE(ItemNotFoundError,ITEM,PyErrK);
  RETURN LST;
 END;
 
 EXPORT Pyreverse (LST)
 BEGIN
  RETURN REVERSE(LST);
 END;

 EXPORT Pysort(LST,KeyFunc,RReverse)
 //TBD: KeyFunc: Selects sort key from itapprox()
 BEGIN
  IF TYPE(KeyFunc)==DOM_FLOAT-1 AND KeyFunc==0 THEN
   //0=None=NO FUNC
  ELSE
   TBD();
   RAISE(ValueError,"Pysort",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,4);//40
  LST(2):="21. ListREMOVEDUPLICATES";
  LST(3):="32. ListGETLIST";
  LST(4):="40. ListREMOVEITEM";
  CHOOSE(VR,"Puzzles",LST);
 END;

 EXPORT ListPythonAnalogues ()
 BEGIN
  LOCAL KK;
  LOCAL PyFuns:={"Pyappend",
   "Pyclear","Pycopy","Pycount",
   "Pyextend",
   "Pyindex","Pyinsert",
   "Pypop","Pypoplast",
   "Pyremove","Pyreverse",
   "Pysort"};
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,"Py analogues",PyFuns)

 END;

 EXPORT ListStatisticalFunctions()
 BEGIN
  LOCAL KK;
  //Just listed to group these Not choosable
  CHOOSE(KK,"Statistical Functions",
   {"ListMEAN","ListMEAN2",
    "ListMEDIAN","ListMEDIAN2",
    "ListMODE","ListMODE2"});
 END;

 
 EXPORT ListExamples()
 //In real use, use XXX:=List...()
 BEGIN
  LOCAL LL:={1,2,3,4,5,6,7,8,9};
  PRINT();
  PRINT(ListVERSION);
  //PRINT("A");
  PRINT(ListAFTER(LL,2));
  PRINT(ListANDBOOL({1,12},{0,1},"122"));
  PRINT(ListANDBOOL({"AA","BB"},{0,1},"CHAR(0)"));
  PRINT(ListBEFORE(LL,2));
  //PRINT("C");
  PRINT(ListCOUNT({},2));
  PRINT(ListCOUNTANYDUPLICATES_SORTED({}));
  PRINT(ListCOUNTANYDUPLICATES({0,2,2,2}));
  PRINT(ListCOUNTITEM(LL,2));
  PRINT(ListCOUNTITEMS(LL,{2,3}));
  PRINT(ListDIFFER2(LL,CONCAT(LL,2)));
  //PRINT("F");
  PRINT(ListFIND(LL,2));
  PRINT(ListGETLIST(LL,{5,3}));
  PRINT(ListHEAD(LL));
  //PRINT("I");
  PRINT(ListINDEX(LL,2));
  PRINT(ListINSERT(LL,2,4));
  PRINT(ListIsLIST(5));
  PRINT(ListIsNUMERIC({1,2,#3}));
  PRINT(ListIsSET(LL));
  PRINT(ListIsSORTED(LL)); 
  PRINT(ListIsTYPE({"SI"},DOM_STRING-1));
  PRINT(ListMASKBOOL({1,12},{0,1},"122"));
  PRINT(ListMASKBOOL({"AA","BB"},{0,1},"CHAR(0)"));
  PRINT(ListOCCURRENCES(LL));
  PRINT(ListPOP(LL,2));LL:=ListANS;
  PRINT(ListPOPLAST(LL));LL:=ListANS;
  PRINT("R");
  PRINT(ListREMOVEX(LL,2));
  PRINT(ListREMOVE(LL,9));
  PRINT(ListSHUFFLE(−52));
  PRINT(ListSHUFFLE(52));
  PRINT(ListSHUFFLE({"R","G","B"}));
  PRINT(ListSLICE({1,2,3,4},2,3));
  PRINT(ListSORT(LL));
  PRINT(ListTAIL(LL));
  PRINT(ListToSET({1,2,2}));
 
  PRINT(ListMEAN(LL));
  PRINT(ListMEDIAN(LL));
  PRINT(ListMODES({"AC","DC"})); 
 
  PRINT("Exampled");
  //RETURN ListCOUNT({1,2,2,2},2);
 END;

 EXPORT LIST()
 BEGIN
  ABOUT();
  //ListExamples();
 END;


Empty lists are now handled or raise errors as appropriate.

Stephen Lewkowicz (G1CMZ)
Visit this user's website Find all posts by this user
Quote this message in a reply
11-16-2017, 10:04 PM
Post: #4
RE: List API (G1CMZ): List Processing API
Version 1.1: Some new procedures and performance improvements, including useful contributions from the forum.

Code:


 LOCAL CRID:="List API V1.1 © 2017 StephenG1CMZ";
 LOCAL MORETEXT:="A collection of list routines brought to you by StephenG1CMZ,\n with some from the forum.";
 
 //Customise
 EXPORT ListShowErrors:=1;//SHOW ERRORS
 EXPORT ListNumericTypes:={DOM_FLOAT-1,DOM_INT-1,DOM_COMPLEX-1,DOM_MATRIX-1};
 //Query: Include COMPLEX,LONGFLOAT,MATRIX?
 EXPORT ListSortableTypes:={DOM_FLOAT-1,DOM_INT-1,3-1};//3-1=MAGIC NUMBER FOR STRINGS NOT DOM_STRING=12 NOT COMPLEX MATRIX OR LIST
  //NB To test: sort >1 item
 //End

 //Forward
 ListCOUNTANYDUPLICATES_SORTED(SORTEDLST);
 ListCOUNTITEM(LST,ITEM);
 ListCOUNTITEMS(LST,ITEMS);
 ListIsTYPE(LST,TYPES);
 ListOCCURRENCES(LST);
 ListREMOVEDUPLICATES(LST);
 ListREMOVEX(LST,POSN);
 ListSORT(LST);
 ListSORTN(LST,NN);

 //NB In main routines (ie not Python)
 //POSN parameter is >=0 (0=LAST)
 //POSN returned is ≥0 (PPL,0=NOTIN)

 //LOCAL SL:=1;
 LOCAL NL:="\n";

 LOCAL MN:="List.";//Name
 LOCAL EMPTY0:=0;//ADDITIVE
 LOCAL EMPTY1:=1;//MULTIPLICATIVE

//TO REFER TO ListTYPE, USE DOM_LIST-1; MAGIC NUMBER FOR LISTS.

 LOCAL ListANS;//OUTPUT LIST(WHEN NOT RETURNED)
  //Also, useful temporary results 

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

 TBD()
 BEGIN
  MSGBOX(MN+"TBD");
 END;
 
 EXPORT RAISE(MN,ERRLST,ERR,CULPRIT,SEVERITY)
 //Only exported for testing
 BEGIN
  IF ListShowErrors AND SEVERITY>0 THEN
   MSGBOX(MN+" "+ERRKIND(SEVERITY+1)+NL+EL(ERR)+NL+CULPRIT);
  END;
  ListLastError:=ERR;
 END;

 NAN()
 BEGIN
  RETURN NaN;
 END;

 //MAINLY STANDARD FUNCTIONS

 EXPORT ListΣLIST(LST)
 BEGIN
  RETURN IFTE(SIZE(LST),ΣLIST(LST),EMPTY0); 
 END;

 EXPORT ListΠLIST(LST)
 BEGIN
  LOCAL SZ:=SIZE(LST);
  
  IF SZ>1 THEN RETURN ΠLIST(LST);
  END;
  IF SZ==1 THEN RETURN LST(1);
  END;
  //IF SZ==0 THEN
  RETURN EMPTY1;
  //END;
 END;

 EXPORT ListAFTER(LST,POSN)
 //Slice After POSN:
 //POSN=0 OR LAST:{}
 BEGIN
  LOCAL FRM:=POSN+1;
  RETURN IFTE((POSN==0 OR FRM>SIZE(LST)),{},LST({FRM,SIZE(LST)}));
 END;

 EXPORT ListANDBOOL(LST,LSTBOOL,NewValue)
 //Replace items ANDed out with NULL(NewValue)
 //EG ({"AA","BB"},{0,1},"CHAR(0)") = {"","BB"}//Note the quotes
 //EG ({11,13},{0,1},"12")//NOMORETHAN12
 //RequirementSpec:
 //http://www.hpmuseum.org/forum/thread-5092.html
 //Usage:
 //http://www.hpmuseum.org/forum/thread-5031.html
 //See also:MaskBOOL
 //NULL=NULL
 BEGIN
  //Guard against empty "" giving syn err
  LOCAL MYNULL:=IFTE(NewValue=="","CHAR(0)",NewValue);
  IF SIZE(LST) AND SIZE(LSTBOOL) THEN
   RETURN EXECON("IFTE(&2,&1,"+MYNULL+")",LST,LSTBOOL);
  END;
  RETURN {};
 END;

 EXPORT ListAPPEND(LST,ITEM)
 //APPEND ITEM TO LIST
 //EG L2:=APPEND(L2,3)
 //PPL:L2(0):=3;
 //Py:APPEND(L2,3)
 //NULL: {ITEM}
 // (LST,{ITEMLST}) ADDS 1 ITEM (A LST)
 BEGIN
  RETURN LST(0):=ITEM; 
 END;

 EXPORT ListBEFORE(LST,POSN)
 //Slice Before POSN: 
 //POSN=0: ({1,2},0)={1}
 BEGIN
  LOCAL TOO:=POSN-1;
  IF POSN==0 THEN
    RETURN ListBEFORE(LST,SIZE(LST));
  END;
  RETURN IFTE(TOO>0,LST({1,TOO}),{});
 END;

 EXPORT ListCONCAT(LST1,LST2)
 //CONCATENATE
 BEGIN
  CONCAT(LST1,LST2);
 END;

 EXPORT ListCOUNT (LST,ITEM)
 //COUNT 1 ITEM:(WHICH MAY BE A LIST)
 BEGIN  
  RETURN ListCOUNTITEMS(LST,{ITEM});
 END;

 EXPORT ListCOUNTANYDUPLICATES(LST)
 //Current Implementation yields a sorted LST
 //But might change
 BEGIN
  ListANS:=ListSORT(LST);
  RETURN ListCOUNTANYDUPLICATES_SORTED(ListANS);
 END;

 EXPORT ListCOUNTANYDUPLICATES_SORTED(SortedLST)
 //Count how many duplicates in a sortedlist,Return a REAL INT
 //({1,9,9}=1 dup, {1,2,2,3,3,3}=3 dup)
 BEGIN
  LOCAL II;
  LOCAL DUPCOUNT:=0;
  IF SIZE(SortedLST)>1 THEN
   FOR II FROM 1 TO SIZE(SortedLST)-1 DO
    IF SortedLST(II) ==SortedLST(II+1) THEN
     DUPCOUNT:=DUPCOUNT+1;
    END;//IF
   END;//FOR
   //ELSE:SMALL LISTS HAVE NO DUPLICATES
  END;//IF
  RETURN DUPCOUNT;
 END;

 EXPORT ListCOUNTITEMS(LST,ITEMS)
 //ITEMS MAY BE 1 ITEM OR A LIST OF SEPARATE ITEMS
 //SO TO COUNT LISTS, CONTAIN THEM IN A LIST
 //EG {1,{},2},{{}}= 1
 //EG {1,2,3},{2,3} = 2
 //EG {1,{2,3}},{2,3} = 0 (TO SEARCH FOR ITEM {2,3} USE COUNT)
 //ITEMS NULL=0
 //LST NULL=0
 BEGIN
  RETURN SIZE(INTERSECT(LST,ITEMS));
 END;
 
 EXPORT ListDIFFER2(LST1,LST2)
 //POSITION OF 1st DIFFERENCE
 //FLOAT≠INTEGER
 //SIZE≠SIZE: SZ+1 RETURNED(UNLESS EARLIER DIFFERENCE)
 BEGIN
  LOCAL II:=1;
  LOCAL SZ:=MIN(SIZE(LST1),SIZE(LST2));

  IF EQ(LST1,LST2) THEN
   RETURN 0;
  END;
  //IF SIZE(LST1)≠SIZE(LST2) THEN
  // RETURN −1;
  //END;
  WHILE II≤SZ DO
   IF TYPE(LST1)≠TYPE(LST2) OR LST1(II)≠LST2(II) THEN
    RETURN II;
   END;
   II:=II+1;
  END; 
  RETURN IFTE(SIZE(LST1)>SZ OR SIZE(LST2)>SZ,SZ+1,0);
 END;

 EXPORT ListFIND(LST,ITEM)
  //See http://www.hpmuseum.org/forum/thread-9431.html
 BEGIN 
  LOCAL X,Y;
  LOCAL LSTPOSNS={};

  WHILE X:=POS(LST,ITEM) DO
    LSTPOSNS(0):=(Y:=X+Y);
    LST:=LST({X,SIZE(LST)}+1)
  END;
  RETURN LSTPOSNS;
 END;
 
 EXPORT ListGETLIST(LST,GETLST)
 //Solves Puzzle #32. POSN≥0.
 //POSN>SIZE(LST):EXCEPTION. RETURN {} FOR THAT ITEM
 BEGIN
 LOCAL II;

  IF SIZE(GETLST) THEN
   IF MAX(GETLST)>SIZE(LST) THEN
    RAISE(MN+"ListGETLIST",EL,IndexOutOfBoundsException,MAX(GETLST)+">"+SIZE(LST),ListErrK);
   END;
   //IFTE GUARDS INDEX>SIZE(LST)
   RETURN MAKELIST(IFTE(GETLST(II)>SIZE(LST),{},LST(GETLST(II))),II,1,SIZE(GETLST));
  END;
  RETURN {};//ASKED TO GET NOTHING
 END;

 EXPORT ListHEAD(LST)
 //List HEAD AKA LISP CAR
 //NULL:ERR
 BEGIN
  IF SIZE(LST) THEN
   RETURN LST(1);
  END;
  RAISE(MN+"ListHEAD",EL,ListIsEmptyError,"",ListErrK);
  RETURN {};
 END;

 EXPORT ListINDEX(LST,ITEM)
 //Despite the confusing name
 //Simple: Return posn of 1st instance of item
 //NULL: 0
 BEGIN
  RETURN POS(LST,ITEM);
 END;

 EXPORT ListINSERT(LST,POSN,ITEM)
 //INSERT ITEM BEFORE POSN
 //PPL POSN=0 = APPEND
 //Py  POSN=0 = 1ST
 BEGIN
  LOCAL POSNB:=POSN-1;
  LOCAL LSTB:=IFTE(POSN==1,{},LST({1,POSNB}));
  LOCAL LSTA:=LST({POSN,SIZE(LST)});

  IF POSN==0 THEN //IN PPL:
   //IT IS UNCLEAR WHETHER THIS SHOULD APPEND,
   //OR INSERT BEFORE LAST 
   //OPINIONS?
   //TBD();
   RETURN CONCAT(LST,ITEM);
  END;
  RETURN CONCAT(CONCAT(LSTB,ITEM),LSTA);
 END;

 //Query:
 //IsLIST ask-Is parameter this
 //IsNUMERIC,IsSET,IsSORTABLE,IsTYPE ask:Are contents this
 //Change names to clarify?

 EXPORT ListIsLIST(LST)
 //BOOL:Is actual parameter a list_type
 //In PPL lists and sets both 1
 //To check instead that a list contains only lists,
 //use IsTYPE(LST,{DOM_LIST})
 BEGIN
   RETURN (TYPE(LST)==DOM_LIST-1);
 END;

 EXPORT ListIsNUMERIC(LST)
 //Is list currently numeric
 BEGIN 
  RETURN ListIsTYPE(LST,ListNumericTypes);
 END;

 EXPORT ListIsSET(LST)
 //BOOL:Is LST currently a set (no duplicates)
 //A uniquelist (no duplicates) may be a set
 //NULL:1
 BEGIN
  RETURN NOT(ListCOUNTANYDUPLICATES(LST));
 END;

 EXPORT ListIsSORTABLE(LST)
 //0.Is parameter a list
 //1.Is TYPE of contents OF ORDERABLE DATA
 //2.Is ListSORT 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

 BEGIN
  IF TYPE(LST)==DOM_LIST-1 THEN
   RETURN ListIsTYPE(LST,ListSortableTypes);
  END;
  RETURN 0;//NO LIST:CANNOT BE SORTED
 END;

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

 EXPORT ListIsTYPE(LST,TYPES)
 //TYPES: TYPE OR LIST OF TYPES
 //SEE ALSO:IsNUMERIC
 //MAKELIST IS FASTER THAN [FOR,INCREMENT COUNT] 
 BEGIN
  LOCAL II;

  IF TYPE(TYPES)==DOM_FLOAT-1 THEN RETURN ListIsTYPE(LST,{TYPES});
  END;
 
  IF SIZE(LST) AND SIZE(TYPES) THEN
   ListANS:=MAKELIST(IFTE(POS(TYPES,TYPE(LST(II))),1,0),II,1,SIZE(LST));//List matching types
   RETURN IFTE(ΣLIST(ListANS)==SIZE(LST),1,0); //Count them
  END;
  RAISE(MN+"ListIsTYPE",EL,ListIsEmptyError,"",1);
  //EMPTY LST: LST ALWAYS INDETERMINATE (GUARD) 
  //EMPTY TYPES: 0>NO MATCHES OR 1>NO REJECTS 
  RETURN 0;//INDETERMINATE
 END;

 EXPORT ListMASKBOOL(LST,LSTBOOL,NewValue)
 //Mask selected values
 //Cf ANDBOOL
 //Here 1 selects replace, not 0
 //NULL=NULL
 BEGIN 
  //Guard against empty "" giving syn err
  LOCAL MYNULL:=IFTE(NewValue=="","CHAR(0)",NewValue);
  IF SIZE(LST) AND SIZE(LSTBOOL) THEN
   RETURN EXECON("IFTE(&2,"+MYNULL+",&1)",LST,LSTBOOL);
  END;
  RETURN {};
  //Equivalent to
  //RETURN ListANDBOOL(LST,NOT(LSTBOOL),NewValue);
 END;

EXPORT ListMAX(LST)
BEGIN
  RETURN IFTE(SIZE(LST),MAX(LST),EMPTY0);
END;

 EXPORT ListMEAN(LST)
 BEGIN
  IF SIZE(LST) THEN
   RETURN (mean(LST));
  END;
  RAISE(MN+"ListMEAN",EL,ListIsEmptyError,"",ListErrK);
  RETURN NAN();
 END;
 //NB MEAN AND MEAN2 CURRENTLY RETURN TYPE RAT
 //USE approx if you prefer real
 EXPORT ListMEAN2(LSTV,LSTF)
 BEGIN
  IF SIZE(LSTV) AND SIZE(LSTF) THEN
   RETURN (mean(LSTV,LSTF));
  END;
  RAISE(MN+"ListMEAN2",EL,ListIsEmptyError,"",ListErrK);
  RETURN NAN();
 END;

 EXPORT ListMEDIAN(LST)
 BEGIN
  IF SIZE(LST) THEN
   RETURN(median(LST));
  END;
  RAISE(MN+"ListMEDIAN",EL,ListIsEmptyError,"",ListErrK);//(NO MEDIAN)
  RETURN NAN();///
 END;

 EXPORT ListMEDIAN2(LSTV,LSTF)
 BEGIN
  IF SIZE(LSTV) AND SIZE(LSTF) THEN
   RETURN(median(LSTV,LSTF));
  END;
  RAISE(MN+"ListMEDIAN2",EL,ListIsEmptyError,"",ListErrK);
  RETURN NAN();///
 END;

 EXPORT ListMIN(LST)
 BEGIN
  RETURN IFTE(SIZE(LST),MIN(LST),EMPTY0);
 END;

 EXPORT ListMODE(L)
 //From http://www.hpmuseum.org/forum/thread-9393.html
 BEGIN
 LOCAL l1,l2;
 l1:=UNION(L);
 l2:=MAKELIST(SIZE(INTERSECT(L,l1(I))),I,1,SIZE(l1));
 l2:=(l2==MAX(l2))*MAKELIST(I,I,1,SIZE(l1));
 l2:=remove(0,l2);
 MAKELIST(l1(l2(I)),I,1,SIZE(l2));
END;
   
 //MODE1_DEPRECATED is deprecated as it is slower
 //MODE2 is likely slower too,
 //but may be useful as parameters differ
 //(retain for comparisons speed and testing)    

 EXPORT ListMODE2(LSTV,LSTF)
 //Get MODES of ItemXFrequency Lists
 //Empty=Empty
 BEGIN
  LOCAL II;
  LOCAL MODESLST:={};
  LOCAL MODEPOSNS:={};

  IF SIZE(LSTF) AND SIZE(LSTV) THEN
   //Find MODES
   MODEPOSNS:=ListFIND(LSTF,MAX(LSTF));
  
   FOR II FROM 1 TO SIZE(MODEPOSNS) DO
    MODESLST(II):=LSTV(MODEPOSNS(II));
   END;//FOR
  END;//IF
  RETURN MODESLST;
 END;

 EXPORT ListMODE1_DEPRECATED(LST)
 //Get MODES of LST : Empty = Empty
 BEGIN
  //Make uniquelst and count
  ListANS:=ListOCCURRENCES(LST);
  
  RETURN ListMODE2(ListANS(1),ListANS(2));
 END;

 EXPORT ListOCCURRENCES(LST)
 //Given a list
 //Return unique list of occurrences and their occurrence counts as 2 lists
 BEGIN
  LOCAL II;
  LOCAL LSTF:={};
  LOCAL LSTV:=ListREMOVEDUPLICATES(LST);

  FOR II FROM 1 TO SIZE(LSTV) DO
   LSTF(II):=ListCOUNT(LST,LSTV(II));
  END;
  RETURN {LSTV,LSTF};
 END;

 EXPORT ListOCCURRENCESWITHSORT(LST)
 //As OCCURRENCES but the LSTV output is sorted
 //Puzzle #31
 //This trivial implement is quicker than sorting output lists using SORTN
 //(but using SORTN makes selecting sorting by list2 easier)
 //See also: ListSORTBYOCCURRENCES
 BEGIN
  RETURN ListOCCURRENCES(ListSORT(LST));
 END;

//There must be a better name
 EXPORT ListInvOCCUR(LSTV,LSTF)
 //INVERSE OF OCCURRENCES
 //Given V and F yield V,F times
 //NULL=NULL
 //In an OCCURRENCES list V is unique and F>0
 //But We handle V with F=0 and V nonunique
 BEGIN
  LOCAL II,JJ;
  LOCAL LST:={};

  FOR II FROM 1 TO SIZE(LSTV) DO
   IF LSTF(II) THEN //V WITH F>0
    LST:=CONCAT(LST,MAKELIST(LSTV(II),JJ,1,LSTF(II)));
   END;
  END;
 
  RETURN LST;
 END;

 EXPORT ListPOP(LST,POSN)
 //POP POSN OFF LIST
 BEGIN
  LOCAL ITEM;
  IF SIZE(LST) THEN
   ITEM:=LST(IFTE(POSN,POSN,SIZE(LST)));//0=>LAST
   ListANS:=ListREMOVEX(LST,POSN);
  ELSE
   RAISE(MN+"ListPOP",EL,ListIsEmptyError,"",ListErrK);
   ITEM:={};
   ListANS:={};
  END;   
  //RETURN POPPED ITEM
  //BUT ALSO SAVE SHORTENED LST
  RETURN ITEM;
 END;

 EXPORT ListPOPLAST(LST)
 //POP POSN OFF LIST
 //Py: POP()
 BEGIN
  RETURN ListPOP(LST,SIZE(LST)); 
 END;

 EXPORT ListremoveX(LST,POSN)
 // CAS ALTERNATIVE TO REMOVEX:MAY BE SLOW
 //See 
 //http://www.hpmuseum.org/forum/thread-9406.html and
 //http://www.hpmuseum.org/forum/thread-7987.html?highlight=suppress 
 //NULL=NULL,POSN>SZE=LST
 BEGIN
  IF POSN THEN
   RETURN suppress(LST,POSN);
  END;
  RETURN suppress(LST,SIZE(LST));//0=LAST
 END;

 EXPORT ListREMOVEX(LST,POSN)
 //REMOVE 1 ITEM AT POSN
 //NULL=NULL,POSN>SIZE=LST (NOWT REMOVED)
 BEGIN
  LOCAL LSTB,LSTA;

  IF POSN THEN
   LSTB:=ListBEFORE(LST,POSN);
   LSTA:=ListAFTER (LST,POSN);
   RETURN CONCAT(LSTB,LSTA);
  ELSE
   //PPL: 0=Remove Last Item
   RETURN ListREMOVEX(LST,SIZE(LST));
   //Py: 0=RemoveFirst ie return TAIL
  END;
 END;
 
 EXPORT Listremove(LST,ITEM) 
 //CAS version slower
 //NULL=NULL
 BEGIN
  RETURN remove(ITEM,LST);
 END;

 EXPORT ListREMOVE(LST,ITEM)
 //Remove 1 instance of ITEM
 //NULL=NULL 
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  IF POSN THEN
   RETURN ListREMOVEX(LST,POSN);
  END;
  RAISE(MN+"ListREMOVE",EL,ItemNotFoundError,ITEM,0);
  RETURN LST;//NOTHING TO REMOVE
 END;

 EXPORT ListREMOVEDUPLICATES(LST)
 //RESULT WITH DUPLICATES JUST ONCE 
 //Native: Sequence NOT determined but seems same
 //From #21
 BEGIN
  RETURN UNION(LST);
 END;

 EXPORT ListREMOVEDUPLICATESSL(LST)
 //SL
 //My own implementation ensures known list sequence (per original LST)
 BEGIN
  LOCAL II;
  LOCAL ListANS:={};

  FOR II FROM 1 TO SIZE(LST)  DO
   IF POS(ListANS,LST(II))==0 THEN //NOT YET LISTED
    ListANS(0):=LST(II);//ADD ENTRY
   END;
  END;
  RETURN ListANS;//EACH ITEM ONCE
 END;

 EXPORT ListREMOVEITEM(LST,ITEM)
 //ALL INSTANCES.PUZZLE #40.
 BEGIN
  LOCAL II;
  LOCAL FOUND:=ListFIND(LST,ITEM);
  IF SIZE(FOUND) THEN
   ListANS:=LST;
   //Remove from right:earlier posns unchanged
   FOR II FROM SIZE(FOUND) DOWNTO 1 DO
    ListANS:=ListREMOVEX(ListANS,FOUND(II));
   END;
   RETURN ListANS;
  END;//IF
  RETURN LST;//NOTHING REMOVED 
 END;

 EXPORT ListREPLACE(LST,ITEM,ITEM2)
 //Replace instances of ITEM with ITEM2
 BEGIN
  LOCAL II;
  LOCAL FOUND:=ListFIND(LST,ITEM);
  IF SIZE(FOUND) THEN
   ListANS:=LST;
   FOR II FROM 1  TO SIZE(FOUND)  DO
    ListANS(FOUND(II)):=ITEM2;
   END;
  ELSE
   RETURN LST;
  END;
  RETURN ListANS; 
 END;

 EXPORT ListSHUFFLE(LST_NUM)
 //SHUFFLE NUM: SHUFFLE 1..N INDEXES 
 //SHUFFLE LST: SHUFFLE LST
 //N<0:GUARD:UNSHUFFLED INDEX
 //NULL OR 0 OR >10000: NULL 
 BEGIN
  LOCAL II,NUM;
  IF TYPE(LST_NUM)=DOM_FLOAT-1 THEN
   NUM:=IFTE(LST_NUM>10000,0,LST_NUM);
   IF LST_NUM<0 THEN //GUARD NEGATIVES (AVOID CRASH)
    RETURN MAKELIST(II,II,1,ABS(NUM));//UNSHUFFLED
   END;
  END;
  RETURN mat2list(randperm(LST_NUM));
 END;

 EXPORT ListSLICE(LST,FRM,TOO)
 //RETURN PART OF LIST (AKA SUB)
 //SYNTAX HINT
 //SUGGEST ALSO IMPL (LST,{2,[3]})
 //FRM≤TOO:Bad Inputs={}
 BEGIN
  LOCAL TTOO:=IFTE(TOO==0,SIZE(LST),TOO); //TO 0==LAST
  LOCAL TFRM:=IFTE(FRM==0,SIZE(LST),FRM); //FRM 0==LAST
  //MSGBOX("SLICE "+{FRM,TOO});
  IF TFRM>TTOO THEN
    //RAISE(IndexOutOfBoundsException,FRM,ListErrK);//Maybe a new error
    RETURN {};
  END; 
  RETURN LST({TFRM,TTOO});
 END;

 EXPORT ListSORT(LST)
 //This implementation uses native SORT
 //On old compilers See known bugs 
 //This will not affect MODE other than changing ordering 
 //Native SORT falls over:Use IsSORTABLE to check 1st
 //NOTET TO DEVELOPERS:
 //NB1:Sorting a list of size 1 is trivial, so test using 2to see if a t 
 BEGIN
  IF TYPE(LST)≠DOM_LIST-1 THEN 
   RAISE(MN+"ListSORT",EL,ListSortError,"",ListErrK);
  END;
  RETURN SORT(LST);
 END;

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

 EXPORT ListSORTN(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 ListSORTBYOCCURRENCES(LST)
 //reverse so most popular is 1st and index is approx rank 
 BEGIN
  ListANS:=ListOCCURRENCES(LST);
  RETURN REVERSE(ListSORTBYKEY(ListANS,2));
 END;

 EXPORT ListTAIL(LST)
 //List TAIL AKA LISP CDR
 //NULL:ERR
 //(SOME USE TAIL=LAST NOT TAIL=CDR)
 BEGIN
  IF SIZE(LST) THEN
   RETURN LST({2,SIZE(LST)});
  END;
  RAISE(MN+"ListTAIL",EL,ListIsEmptyError,"",ListErrK);
  RETURN {};
 END;

 EXPORT ListToSET(LST)
 //In addition to making the list like a set
 //wibni we could track those tnat ARE sets
 BEGIN
  RETURN ListREMOVEDUPLICATES(LST);
 END;

 EXPORT ListVERSION()
 BEGIN
  RETURN CRID;
 END;

 // Python names(LC) prefixed Py ()
 // Py  syntax: Lst.append(ITEM) etc 
 // PPL syntax: Lst:=append(Lst,ITEM)
 // Py indexes from 0 but not yet implemented
 // These names are inspired by Py, 
 // but will never provide exact equivalents.
 
 //Currently,0 is Py-like but other indexes are not.
 //Thus it achieves incompatability with 
 //PPL(0), Python (≠0) and CAS-Python:S-Beta (like PPL, supposedly).
 //Indexing is therefore likely to change here.

 EXPORT Pyappend(LST,ITEM)
 //append a single item
 BEGIN 
  RETURN append(LST,ITEM);//CAS
 END;

 EXPORT Pyclear(LST)
 //Py :ALSO DELETES LIST (cf CAS purge)
 BEGIN 
  RETURN {};
 END;

 EXPORT Pycopy(LST)
 //Py: A shallow copy PPL: simple copy
 BEGIN
  RETURN LST;
 END;

 EXPORT Pycount(LST,ITEM)
 //Py :Count occurences of item
 BEGIN
  RETURN ListCOUNT(LST,ITEM);
 END;

 EXPORT Pyextend(LST,LST2)
 //Py :Concat items in LST2 to LST
 //Query: If listfull, should we add some or none
 //PPL:LST2 may be an item 
 BEGIN
  CONCAT(LST,LST2);
 END;

 EXPORT Pyindex(LST,ITEM)
 //Py :Return index (or ValueErr)

 //TBD START:END LIMIT RANGE SEARCHED WITHOUT CHANGING INDEX
 BEGIN
  LOCAL LX:=ListINDEX(LST,ITEM); 
  IF LX==0 THEN
   RAISE(MN+"Pyindex",EL,ValueError,ITEM,PyErrK);//Py:NotFound => an error
  END;
  RETURN LX; 
 END;

 EXPORT Pyinsert(LST,POSN,ITEM)
 //Py :Insert ITEM before POS
 BEGIN
  IF POSN==0 THEN
   TBD();
   CONCAT(ITEM,LST);//Py 0
  END;
  RETURN ListINSERT(LST,POSN,ITEM); 
 END;

 EXPORT Pypop(LST,POSN)
 //Py :Pop item (Posn Omit:Last)
 //PPL:Posn reqd
 BEGIN
  IF POSN==0 THEN
   TBD();
  END;
  RETURN ListPOP(LST,POSN);
 END;

 EXPORT PypopLast(LST)
 //Py :Pop item (Posn Omit:Last)
 //PPL:Twofunctions
 BEGIN
  RETURN ListPOPLAST(LST);
 END;

 EXPORT Pyremove(LST,ITEM)
 //Py :Remove 1st ITEM,ERR IF NONE
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  IF POSN THEN
   RETURN ListREMOVEX(LST,POSN);
  END;
  //ELSE NOTHING TO REMOVE
  RAISE(MN+"Pyremove",EL,ItemNotFoundError,ITEM,PyErrK);
  RETURN LST;
 END;
 
 EXPORT Pyreverse (LST)
 BEGIN
  RETURN REVERSE(LST);
 END;

 EXPORT Pysort(LST,KeyFunc,RReverse)
 //TBD: KeyFunc: Selects sort key from itapprox()
 BEGIN
  IF TYPE(KeyFunc)==DOM_FLOAT-1 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,4);//40
  LST(1):="21. ListREMOVEDUPLICATES";
  LST(2):="31. ListOCCURRENCESWITHSORT";
  LST(3):="32. ListGETLIST";
  LST(4):="40. ListREMOVEITEM";
  CHOOSE(VR,MN+"Puzzles (See thread)",LST);
 END;

 EXPORT ListPythonAnalogues ()
 BEGIN
  LOCAL KK;
  LOCAL PyFuns:={"Pyappend",
   "Pyclear","Pycopy","Pycount",
   "Pyextend",
   "Pyindex","Pyinsert",
   "Pypop","Pypoplast",
   "Pyremove","Pyreverse",
   "Pysort"};
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,MN+" Py analogues",PyFuns)

 END;

 EXPORT ListStatisticalFunctions()
 BEGIN
  LOCAL KK;
  //Just listed to group these Not choosable
  CHOOSE(KK,MN+" Statistical Functions",
   {"ListMEAN","ListMEAN2",
    "ListMEDIAN","ListMEDIAN2",
    "ListMODE","ListMODE1_DEPRECATED","ListMODE2"});
 END;

 EXPORT ListExamples()
 //In real use, use XXX:=List...()
 BEGIN
  LOCAL LL:={1,2,3,4,5,6,7,8,9};
  PRINT();
  PRINT(ListVERSION);
  PRINT("A");
  PRINT(ListAFTER(LL,2));
  PRINT(ListANDBOOL({1,12},{0,1},"122"));
  PRINT(ListANDBOOL({"AA","BB"},{0,1},"CHAR(0)"));
  PRINT("B");
  PRINT(ListBEFORE(LL,2));
  PRINT("C");
  PRINT(ListCOUNT({},2));
  PRINT(ListCOUNTANYDUPLICATES_SORTED({}));
  PRINT(ListCOUNTANYDUPLICATES({0,2,2,2}));
  PRINT(ListCOUNTITEMS(LL,{2,3}));
  PRINT("D");
  PRINT(ListDIFFER2(LL,CONCAT(LL,2)));
  PRINT("FG");
  PRINT(ListFIND(LL,2));
  PRINT(ListGETLIST(LL,{5,3}));
  PRINT("HI");
  PRINT(ListHEAD(LL));
  PRINT(ListINDEX(LL,2));
  PRINT(ListINSERT(LL,2,4));
  PRINT("Is");
  PRINT(ListIsLIST(5));
  PRINT(ListIsNUMERIC({1,2,#3}));
  PRINT(ListIsSET(LL));
  PRINT(ListIsSORTED(LL)); 
  PRINT(ListIsTYPE({"SI"},DOM_STRING-1));
  PRINT("MNO");
  PRINT(ListMASKBOOL({1,12},{0,1},"122"));
  PRINT(ListMASKBOOL({"AA","BB"},{0,1},"CHAR(0)"));
  PRINT(ListOCCURRENCES(LL));
  PRINT("P");
  PRINT(ListPOP(LL,2));LL:=ListANS;
  PRINT(ListPOPLAST(LL));LL:=ListANS;
  PRINT("R");
  PRINT(ListREMOVEX(LL,2));
  PRINT(ListREMOVE(LL,9));
  PRINT("S");
  PRINT(ListSHUFFLE(−52));
  PRINT(ListSHUFFLE(52));
  PRINT(ListSHUFFLE({"R","G","B"}));
  PRINT(ListSLICE({1,2,3,4},2,3));
  PRINT(ListSORT(LL));
  PRINT("T");
  PRINT(ListTAIL(LL));
  PRINT(ListToSET({1,2,2}));
  PRINT("STATS");
  PRINT(ListMEAN(LL));
  PRINT(ListMEDIAN(LL));
  PRINT(ListMODE({"AC","DC"})); 
 
  PRINT("Exampled");
  //RETURN 0; 
 END;

 EXPORT LIST()
 BEGIN
  ABOUT();
  //ListExamples();
 END;

Note that the indexing used in the Python analogues included here is not currently compatible with PPL (0-index), with Python (indexing from 0), or with the Python-syntax in CAS that may be in the current Beta (PPL-like, apparrently, though I have not yet had the opportunity to verify). So it may well change in future releases.

Stephen Lewkowicz (G1CMZ)
Visit this user's website Find all posts by this user
Quote this message in a reply
01-04-2018, 10:01 AM (This post was last modified: 09-08-2018 09:53 PM by StephenG1CMZ.)
Post: #5
RE: List API (G1CMZ): List Processing API
Version 1.2 adds some new functions, but moves MEAN and some others to my new MEANS program.
Code:

 LOCAL CRID:="List API V1.2 © 2018 StephenG1CMZ";
 LOCAL MORETEXT:="A collection of list routines brought to you by StephenG1CMZ,\n with some from the forum.";
 
 //Customise
 EXPORT ListShowErrors:=1;//SHOW ERRORS
 EXPORT ListNumericTypes:={DOM_FLOAT-1,DOM_INT-1,DOM_COMPLEX-1,DOM_MATRIX-1};
 //Query: Include COMPLEX,LONGFLOAT,MATRIX?
 EXPORT ListSortableTypes:={DOM_FLOAT-1,DOM_INT-1,3-1};//3-1=MAGIC NUMBER FOR STRINGS NOT DOM_STRING=12 NOT COMPLEX MATRIX OR LIST
  //NB To test: sort >1 item
 //End

 //Forward
 ListCOUNTANYDUPLICATES_SORTED(SORTEDLST);
 ListCOUNTITEM(LST,ITEM);
 ListCOUNTITEMS(LST,ITEMS);
 ListIsTYPE(LST,TYPES);
 ListOCCURRENCES(LST);
 ListREMOVEDUPLICATES(LST);
 ListREMOVEX(LST,POSN);
 ListSORT(LST);
 ListSORTN(LST,NN);

 //NB In main routines (ie not Python)
 //POSN parameter is >=0 (0=LAST)
 //POSN returned is ≥0 (PPL,0=NOTIN)

 //LOCAL SL:=1;
 LOCAL NL:="\n";

 LOCAL MN:="List.";//Name

//TO REFER TO ListTYPE, USE DOM_LIST-1; MAGIC NUMBER FOR LISTS.

 LOCAL ListANS;//OUTPUT LIST(WHEN NOT RETURNED)
  //Also, useful temporary results 

 //ERR 
 LOCAL ListErrK:=1;
 LOCAL PyErrK:=3;
 EXPORT ListLastError:=0;
 LOCAL ERRKIND:={"","Error","","Py Error"};
 //FIX
 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 ListSortError:=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)
 //Only exported for testing
 BEGIN
  LOCAL PROGML:=Programs();
  LOCAL PROGM:=PROGML(1);//NB:THE USER PROGM RUNNING, NOT THAT RAISING THE ERROR :(
  IF ListShowErrors AND SEVERITY>0 THEN
   MSGBOX(PROGM+":"+MN+" "+ERRKIND(SEVERITY+1)+NL+ERRLST(ERR)+NL+CULPRIT);
  END;
  ListLastError:=ERR;
 END;

 //MAINLY STANDARD FUNCTIONS
 //Lowercase names are well defined (described in Wikipedia or Python Docs)
 //UPPERCASE and CamelCase names are more likely to change

 EXPORT ListAFTER(LST,POSN)
 //Slice After POSN:
 //POSN=0 OR LAST:{}
 BEGIN
  LOCAL FRM:=POSN+1;
  RETURN IFTE((POSN==0 OR FRM>SIZE(LST)),{},LST({FRM,SIZE(LST)}));
 END;

 EXPORT ListANDBOOL(LST,LSTBOOL,NewValue)
 //Replace items ANDed out with NULL(NewValue)
 //EG ({"AA","BB"},{0,1},"CHAR(0)") = {"","BB"}//Note the quotes
 //EG ({11,13},{0,1},"12")//NOMORETHAN12
 //RequirementSpec:
 //http://www.hpmuseum.org/forum/thread-5092.html
 //Usage:
 //http://www.hpmuseum.org/forum/thread-5031.html
 //See also:MaskBOOL
 //NULL=NULL
 BEGIN
  //Guard against empty "" giving syn err
  LOCAL MYNULL:=IFTE(NewValue=="","CHAR(0)",NewValue);
  IF SIZE(LST) AND SIZE(LSTBOOL) THEN
   RETURN EXECON("IFTE(&2,&1,"+MYNULL+")",LST,LSTBOOL);
  END;
  RETURN {};
 END;

 
 EXPORT ListBEFORE(LST,POSN)
 //Slice Before POSN: 
 //POSN=0: ({1,2},0)={1}
 BEGIN
  LOCAL TOO:=POSN-1;
  IF POSN==0 THEN
    RETURN ListBEFORE(LST,SIZE(LST));
  END;
  RETURN IFTE(TOO>0,LST({1,TOO}),{});
 END;

 EXPORT ListCONCAT(LST1,LST2)
 //CONCATENATE:BUILTIN
 BEGIN
  CONCAT(LST1,LST2);
 END;

 EXPORT ListCOUNTANYDUPLICATES (LST)
 //Preferred-SORTED
 BEGIN
  ListANS:=ListSORT(LST);
  RETURN ListCOUNTANYDUPLICATES_SORTED(ListANS);
 END;

 EXPORT ListCOUNTANYDUPLICATES_SLOW(LST)
 //Caution can be much slower but may be faster
 //REAL LST NO DUPS:5s 
 //INT LST 8000 DUPS:0.2s
 BEGIN
  RETURN SIZE(LST)-SIZE(ListREMOVEDUPLICATES(LST));
 END;

 EXPORT ListCOUNTANYDUPLICATES_SORTED(SortedLST)
 //Count how many duplicates in a sortedlist,Return a REAL INT
 //({1,9,9}=1 dup, {1,2,2,3,3,3}=3 dup)
 //Timings consistent 0.3s
 BEGIN
  LOCAL II;
  LOCAL DUPCOUNT:=0;
  IF SIZE(SortedLST)>1 THEN
   FOR II FROM 1 TO SIZE(SortedLST)-1 DO
    IF SortedLST(II) ==SortedLST(II+1) THEN
     DUPCOUNT:=DUPCOUNT+1;
    END;//IF
   END;//FOR
   //ELSE:SMALL LISTS HAVE NO DUPLICATES
  END;//IF
  RETURN DUPCOUNT;
 END;

 EXPORT ListCOUNTITEMS(LST,ITEMS)
 //ITEMS MAY BE 1 ITEM OR A LIST OF SEPARATE ITEMS
 //SO TO COUNT LISTS, CONTAIN THEM IN A LIST
 //EG {1,{},2},{{}}= 1
 //EG {1,2,3},{2,3} = 2
 //EG {1,{2,3}},{2,3} = 0 (TO SEARCH FOR ITEM {2,3} USE COUNT)
 //ITEMS NULL=0
 //LST NULL=0
 BEGIN
  RETURN SIZE(INTERSECT(LST,ITEMS));
 END;

 EXPORT ListCSV2LIST()
 //Importing the procedure would introduce a dependency(later?)
 BEGIN
  MSGBOX("To parse CSV files/strings to lists use StephenG1CMZ's CSV program.\n")
 END;

 EXPORT ListDIFFER(LST1,LST2)
 //POSITION OF 1st DIFFERENCE
 //FLOAT≠INTEGER
 //SIZE≠SIZE: SZ+1 RETURNED(UNLESS EARLIER DIFFERENCE)
 BEGIN
  LOCAL II:=1;
  LOCAL SZ:=MIN(SIZE(LST1),SIZE(LST2));

  IF EQ(LST1,LST2) THEN
   RETURN 0;
  END;
  //IF SIZE(LST1)≠SIZE(LST2) THEN
  // RETURN −1;
  //END;
  WHILE II≤SZ DO
   IF TYPE(LST1)≠TYPE(LST2) OR LST1(II)≠LST2(II) THEN
    RETURN II;
   END;
   II:=II+1;
  END; 
  RETURN IFTE(SIZE(LST1)>SZ OR SIZE(LST2)>SZ,SZ+1,0);
 END;

 EXPORT ListFIND(LST,ITEM)
  //See http://www.hpmuseum.org/forum/thread-9431.html
 BEGIN 
  LOCAL X,Y;
  LOCAL LSTPOSNS={};

  WHILE X:=POS(LST,ITEM) DO
    LSTPOSNS(0):=(Y:=X+Y);
    LST:=LST({X,SIZE(LST)}+1)
  END;
  RETURN LSTPOSNS;
 END;
 
 EXPORT ListGETLIST(LST,GETLST)
 //Solves Puzzle #32. POSN≥0.
 //POSN>SIZE(LST):EXCEPTION. RETURN {} FOR THAT ITEM
 BEGIN
 LOCAL II;

  IF SIZE(GETLST) THEN
   IF MAX(GETLST)>SIZE(LST) THEN
    RAISE(MN+"ListGETLIST",EL,IndexOutOfBoundsException,MAX(GETLST)+">"+SIZE(LST),ListErrK);
   END;
   //IFTE GUARDS INDEX>SIZE(LST)
   RETURN MAKELIST(IFTE(GETLST(II)>SIZE(LST),{},LST(GETLST(II))),II,1,SIZE(GETLST));
  END;
  RETURN {};//ASKED TO GET NOTHING
 END;

 EXPORT ListHEAD(LST)
 //List HEAD AKA LISP CAR
 //NULL:ERR
 //PPL FASTER
 //See also:head()
 BEGIN
  IF SIZE(LST) THEN
   RETURN LST(1);
  END;
  RAISE(MN+"ListHEAD",EL,ListIsEmptyError,"",ListErrK);
  RETURN {};
 END;

 EXPORT ListINDEX(LST,ITEM)
 //Despite the confusing name
 //Simple: Return posn of 1st instance of item
 //If you do want to index ITEM, use FIND.
 //NULL: 0
 BEGIN
  RETURN POS(LST,ITEM);
 END;


 EXPORT ListINSERT(LST,POSN,ITEM)
 //INSERT ITEM BEFORE POSN
 //PPL POSN=0 = APPEND
 //Py  POSN=0 = 1ST
 BEGIN
  LOCAL POSNB:=POSN-1;
  LOCAL LSTB:=IFTE(POSN==1,{},LST({1,POSNB}));
  LOCAL LSTA:=LST({POSN,SIZE(LST)});

  IF POSN==0 THEN //IN PPL:
   //IT IS UNCLEAR WHETHER THIS SHOULD APPEND,
   //OR INSERT BEFORE LAST 
   //OPINIONS?
   //TBD();
   RETURN CONCAT(LST,ITEM);
  END;
  RETURN CONCAT(CONCAT(LSTB,ITEM),LSTA);
 END;

 //Query:
 //IsLIST asks-Is parameter this
 //IsNUMERIC,IsSET,IsSORTABLE,IsTYPE ask:Are contents this
 //Change names to clarify?

 EXPORT ListIsLIST(LST)
 //BOOL:Is actual parameter a list_type
 //In PPL lists and sets both 1
 //To check instead that a list contains only lists,
 //use IsTYPE(LST,{DOM_LIST})
 BEGIN
   RETURN (TYPE(LST)==DOM_LIST-1);
 END;

 EXPORT ListIsNUMERIC(LST)
 //Is list currently numeric
 BEGIN 
  RETURN ListIsTYPE(LST,ListNumericTypes);
 END;

 EXPORT ListIsSET(LST)
 //BOOL:Is LST currently a set (no duplicates)
 //A uniquelist (no duplicates) may be a set
 //NULL:1
 BEGIN
  RETURN NOT(ListCOUNTANYDUPLICATES(LST));
 END;

 EXPORT ListIsSORTABLE(LST)
 //0.Is parameter a list
 //1.Is TYPE of contents OF ORDERABLE DATA
 //2.Is ListSORT 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

 BEGIN
  IF TYPE(LST)==DOM_LIST-1 THEN
   RETURN ListIsTYPE(LST,ListSortableTypes);
  END;
  RETURN 0;//NO LIST:CANNOT BE SORTED
 END;

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

 EXPORT ListIsTYPE(LST,TYPES)
 //TYPES: TYPE OR LIST OF TYPES
 //SEE ALSO:IsNUMERIC
 //MAKELIST IS FASTER THAN [FOR,INCREMENT COUNT] 
 BEGIN
  LOCAL II;

  IF TYPE(TYPES)==DOM_FLOAT-1 THEN RETURN ListIsTYPE(LST,{TYPES});
  END;
 
  IF SIZE(LST) AND SIZE(TYPES) THEN
   ListANS:=MAKELIST(IFTE(POS(TYPES,TYPE(LST(II))),1,0),II,1,SIZE(LST));//List matching types
   RETURN IFTE(ΣLIST(ListANS)==SIZE(LST),1,0); //Count them
  END;
  RAISE(MN+"ListIsTYPE",EL,ListIsEmptyError,"",1);
  //EMPTY LST: LST ALWAYS INDETERMINATE (GUARD) 
  //EMPTY TYPES: 0>NO MATCHES OR 1>NO REJECTS 
  RETURN 0;//INDETERMINATE
 END;

 EXPORT ListMASKBOOL(LST,LSTBOOL,NewValue)
 //Mask selected values
 //Cf ANDBOOL
 //Here 1 selects replace, not 0
 //NULL=NULL
 BEGIN 
  //Guard against empty "" giving syn err
  LOCAL MYNULL:=IFTE(NewValue=="","CHAR(0)",NewValue);
  IF SIZE(LST) AND SIZE(LSTBOOL) THEN
   RETURN EXECON("IFTE(&2,"+MYNULL+",&1)",LST,LSTBOOL);
  END;
  RETURN {};
  //Equivalent to
  //RETURN ListANDBOOL(LST,NOT(LSTBOOL),NewValue);
 END;

 EXPORT ListMEANS()
 BEGIN
  MSGBOX("StephenG1CMZ's MEANS program implements several means.");
 END;

 EXPORT ListMEDIAN(LST)
 BEGIN
  IF SIZE(LST) THEN
   RETURN(median(LST));
  END;
  RAISE(MN+"ListMEDIAN",EL,ListIsEmptyError,"",ListErrK);//(NO MEDIAN)
  RETURN {};///
 END;
 //Query:What_error to return?
 //NAN OR {} MIGHT BE THE MEDIAN VALUE
 EXPORT ListMEDIAN2(LSTV,LSTF)
 BEGIN
  IF SIZE(LSTV) AND SIZE(LSTF) THEN
   RETURN(median(LSTV,LSTF));
  END;
  RAISE(MN+"ListMEDIAN2",EL,ListIsEmptyError,"",ListErrK);
  RETURN {};///
 END;

 EXPORT ListMODE(L)
 //From http://www.hpmuseum.org/forum/thread-9393.html
 BEGIN
 LOCAL l1,l2;
 l1:=UNION(L);
 l2:=MAKELIST(SIZE(INTERSECT(L,l1(I))),I,1,SIZE(l1));
 l2:=(l2==MAX(l2))*MAKELIST(I,I,1,SIZE(l1));
 l2:=remove(0,l2);
 MAKELIST(l1(l2(I)),I,1,SIZE(l2));
END;
   
 //MODE1_DEPRECATED is deprecated as it is slower
 //MODE2 is likely slower too,
 //but may be useful as parameters differ
 //(retain for comparisons speed and testing)    

 EXPORT ListMODE2(LSTV,LSTF)
 //Get MODES of ItemXFrequency Lists
 //Empty=Empty
 BEGIN
  LOCAL II;
  LOCAL MODESLST:={};
  LOCAL MODEPOSNS:={};

  IF SIZE(LSTF) AND SIZE(LSTV) THEN
   //Find MODES
   MODEPOSNS:=ListFIND(LSTF,MAX(LSTF));
  
   FOR II FROM 1 TO SIZE(MODEPOSNS) DO
    MODESLST(II):=LSTV(MODEPOSNS(II));
   END;//FOR
  END;//IF
  RETURN MODESLST;
 END;

 EXPORT ListMODE1_DEPRECATED(LST)
 //Get MODES of LST : Empty = Empty
 BEGIN
  //Make uniquelst and count
  ListANS:=ListOCCURRENCES(LST);
  
  RETURN ListMODE2(ListANS(1),ListANS(2));
 END;

 EXPORT ListOCCURRENCES(LST)
 //Given a list
 //Return unique list of occurrences and their occurrence counts as 2 lists
 BEGIN
  LOCAL II;
  LOCAL LSTF:={};
  LOCAL LSTV:=ListREMOVEDUPLICATES(LST);

  FOR II FROM 1 TO SIZE(LSTV) DO
   LSTF(II):=ListCOUNT(LST,LSTV(II));
  END;
  RETURN {LSTV,LSTF};
 END;

 EXPORT ListOCCURRENCESWITHSORT(LST)
 //As OCCURRENCES but the LSTV output is sorted
 //Puzzle #31
 //This trivial implement is quicker than sorting output lists using SORTN
 //(but using SORTN makes selecting sorting by list2 easier)
 //See also: ListSORTBYOCCURRENCES
 BEGIN
  RETURN ListOCCURRENCES(ListSORT(LST));
 END;

//There must be a better name
 EXPORT ListInvOCCUR(LSTV,LSTF)
 //INVERSE OF OCCURRENCES
 //Given V and F yield V,F times
 //NULL=NULL
 //In an OCCURRENCES list V is unique and F>0
 //But We handle V with F=0 and V nonunique
 BEGIN
  LOCAL II,JJ;
  LOCAL LST:={};

  FOR II FROM 1 TO SIZE(LSTV) DO
   IF LSTF(II) THEN //V WITH F>0
    LST:=CONCAT(LST,MAKELIST(LSTV(II),JJ,1,LSTF(II)));
   END;
  END;
 
  RETURN LST;
 END;

 EXPORT ListPOP(LST,POSN)
 //POP POSN OFF LIST
 BEGIN
  LOCAL ITEM;
  IF SIZE(LST) THEN
   ITEM:=LST(IFTE(POSN,POSN,SIZE(LST)));//0=>LAST
   ListANS:=ListREMOVEX(LST,POSN);
  ELSE
   RAISE(MN+"ListPOP",EL,ListIsEmptyError,"",ListErrK);
   ITEM:={};
   ListANS:={};
  END;   
  //RETURN POPPED ITEM
  //BUT ALSO SAVE SHORTENED LST
  RETURN ITEM;
 END;

 
 EXPORT ListPOPLAST(LST)
 //POP POSN OFF LIST
 //Py: POP()
 BEGIN
  RETURN ListPOP(LST,SIZE(LST)); 
 END;

 EXPORT ListremoveX(LST,POSN)
 // CAS ALTERNATIVE TO REMOVEX:MAY BE SLOW
 //See 
 //http://www.hpmuseum.org/forum/thread-9406.html and
 //http://www.hpmuseum.org/forum/thread-7987.html?highlight=suppress 
 //NULL=NULL,POSN>SZE=LST
 BEGIN
  IF POSN THEN
   RETURN suppress(LST,POSN);
  END;
  RETURN suppress(LST,SIZE(LST));//0=LAST
 END;

 EXPORT ListREMOVEX(LST,POSN)
 //REMOVE 1 ITEM AT POSN
 //NULL=NULL,POSN>SIZE=LST (NOWT REMOVED)
 BEGIN
  LOCAL LSTB,LSTA;

  IF POSN THEN
   LSTB:=ListBEFORE(LST,POSN);
   LSTA:=ListAFTER (LST,POSN);
   RETURN CONCAT(LSTB,LSTA);
  ELSE
   //PPL: 0=Remove Last Item
   RETURN ListREMOVEX(LST,SIZE(LST));
   //Py: 0=RemoveFirst ie return TAIL
  END;
 END;

 EXPORT ListremoveCAS(LST,ITEM) 
 //CAS version slower
 //NULL=NULL
 BEGIN
  RETURN remove(ITEM,LST);
 END;

 EXPORT ListREMOVE(LST,ITEM)
 //Remove 1 instance of ITEM
 //NULL=NULL 
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  IF POSN THEN
   RETURN ListREMOVEX(LST,POSN);
  END;
  RAISE(MN+"ListREMOVE",EL,ItemNotFoundError,ITEM,0);
  RETURN LST;//NOTHING TO REMOVE
 END;

 EXPORT ListREMOVEDUPLICATES(LST)
 //RESULT WITH DUPLICATES JUST ONCE 
 //Native: Sequence NOT determined but seems same
 //From #21
 BEGIN
  RETURN UNION(LST);
 END;

 EXPORT ListREMOVEITEM(LST,ITEM)
 //ALL INSTANCES.PUZZLE #40.
 BEGIN
  LOCAL II;
  LOCAL FOUND:=ListFIND(LST,ITEM);
  IF SIZE(FOUND) THEN
   ListANS:=LST;
   //Remove from right:earlier posns unchanged
   FOR II FROM SIZE(FOUND) DOWNTO 1 DO
    ListANS:=ListREMOVEX(ListANS,FOUND(II));
   END;
   RETURN ListANS;
  END;//IF
  RETURN LST;//NOTHING REMOVED 
 END;

 //NB replace in CAS is different
 EXPORT ListREPLACE(LST,ITEM,ITEM2)
 //Replace instances of ITEM with ITEM2
 BEGIN
  LOCAL II;
  LOCAL FOUND:=ListFIND(LST,ITEM);
  IF SIZE(FOUND) THEN
   ListANS:=LST;
   FOR II FROM 1  TO SIZE(FOUND)  DO
    ListANS(FOUND(II)):=ITEM2;
   END;
  ELSE
   RETURN LST;
  END;
  RETURN ListANS; 
 END;

 EXPORT ListSHUFFLE(LST_NUM)
 //SHUFFLE NUM: SHUFFLE 1..N INDEXES 
 //SHUFFLE LST: SHUFFLE LST
 //N<0:GUARD:UNSHUFFLED INDEX
 //NULL OR 0 OR >10000: NULL 
 BEGIN
  LOCAL II,NUM;
  IF TYPE(LST_NUM)=DOM_FLOAT-1 THEN
   NUM:=IFTE(LST_NUM>10000,0,LST_NUM);
   IF LST_NUM<0 THEN //GUARD NEGATIVES (AVOID CRASH)
    RETURN MAKELIST(II,II,1,ABS(NUM));//UNSHUFFLED
   END;
  END;
  RETURN mat2list(randperm(LST_NUM));
 END;

 EXPORT ListSLICE(LST,FRM,TOO)
 //RETURN PART OF LIST (AKA SUB)
 //SYNTAX HINT
 //SUGGEST ALSO IMPL (LST,{2,[3]})
 //FRM≤TOO:Bad Inputs={}
 BEGIN
  LOCAL TTOO:=IFTE(TOO==0,SIZE(LST),TOO); //TO 0==LAST
  LOCAL TFRM:=IFTE(FRM==0,SIZE(LST),FRM); //FRM 0==LAST
  //MSGBOX("SLICE "+{FRM,TOO});
  IF TFRM>TTOO THEN
    //RAISE(IndexOutOfBoundsException,FRM,ListErrK);//Maybe a new error
    RETURN {};
  END; 
  RETURN LST({TFRM,TTOO});
 END;

 EXPORT ListSORT(LST)
 //This implementation uses native SORT
 //On old compilers See known bugs 
 //This will not affect MODE other than changing ordering 
 //Native SORT falls over:Use IsSORTABLE to check 1st
 //NOTE TO DEVELOPERS:
 //NB1:Sorting a list of size 1 is trivial, so test using 2to see if a t 
 BEGIN
  IF TYPE(LST)≠DOM_LIST-1 THEN 
   RAISE(MN+"ListSORT",EL,ListSortError,"",ListErrK);
  END;
  RETURN SORT(LST);
 END;

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

 EXPORT ListSORTN(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 ListSORTBYOCCURRENCES(LST)
 //reverse so most popular is 1st and index is approx rank 
 BEGIN
  ListANS:=ListOCCURRENCES(LST);
  RETURN REVERSE(ListSORTBYKEY(ListANS,2));
 END;

 EXPORT ListTAIL(LST)
 //List TAIL AKA LISP CDR
 //NULL:ERR
 //(SOME USE TAIL=LAST NOT TAIL=CDR)
 //PPL FASTER
 //See also:tail
 BEGIN
  IF SIZE(LST) THEN
   RETURN LST({2,SIZE(LST)});
  END;
  RAISE(MN+"ListTAIL",EL,ListIsEmptyError,"",ListErrK);
  RETURN {};
 END;

 EXPORT ListToSET(LST)
 //In addition to making the list like a set
 //wibni we could track those tnat ARE sets
 BEGIN
  RETURN ListREMOVEDUPLICATES(LST);
 END;

 EXPORT ListVERSION()
 BEGIN
  RETURN CRID;
 END;

 // Python names(LC) prefixed Py ()
 // Py  syntax: Lst.append(ITEM) etc 
 // PPL syntax: Lst:=Pyappend(Lst,ITEM)
 // Py indexes from 0 but not yet implemented
 // These names are inspired by Py, 
 // but may never provide exact equivalents.
 
 //Currently,0 and allindexes are PPL-like
 //Thus it achieves compatability with 
 //PPL(0), and CAS-Python:S-Beta (like PPL, supposedly).
 //but not Python

EXPORT Pyappend(LST,ITEM)
 //Python analogue
 //append a single item
 //NB IF List prefix is dropped conflict with CAS.append (CAS.append is slower)
 //NULL LST: {ITEM}
 // (LST,{ITEMLST}) ADDS 1 ITEM (A LST)EG({1},{2,3}={1,{2,3}})
 BEGIN
  RETURN LST(0):=ITEM; 
 END;

 EXPORT Pyclear(LST)
 //Python analogue
 //Py :ALSO DELETES LIST (cf CAS purge)
 BEGIN 
  RETURN {};
 END;

 EXPORT Pycopy(LST)
 //Python analogue
 //Py: A shallow copy PPL: simple copy
 BEGIN
  RETURN LST;
 END;

 EXPORT Pycount (LST,ITEM)
 //Python analogue
 //Count instances of an ITEM:(WHICH MAY BE A LIST=1ITEM)
 //NB do not confuse with CAS.count(Test,Lst)
 BEGIN  
  RETURN ListCOUNTITEMS(LST,{ITEM});
 END;

 EXPORT Pyextend(LST,LST2)
 //Python analogue
 //Py :Concat items in LST2 to LST
 //Query: If listfull, should we add some or none
 //PPL:LST2 may be an item 
 BEGIN
  RETURN CONCAT(LST,LST2);
 END;

 EXPORT Pyindex(LST,ITEM)
 //Python analogue
 //Py :Return index (or ValueErr)

 //TBD START:END LIMIT RANGE SEARCHED WITHOUT CHANGING INDEX
 BEGIN
  LOCAL LX:=ListINDEX(LST,ITEM); 
  IF LX==0 THEN
   RAISE(MN+"Pyindex",EL,ValueError,ITEM,PyErrK);//Py:NotFound => an error
  END;
  RETURN LX; 
 END;

 EXPORT Pyinsert(LST,POSN,ITEM)
 //Python analogue
 //Py :Insert ITEM before POS
 BEGIN
  RETURN ListINSERT(LST,POSN,ITEM); 
 END;

 EXPORT Pypop(LST,POSN)
 //Python analogue
 //Py :Pop item (Posn Omit:Last)
 //PPL:Posn reqd
 BEGIN
  IF POSN==0 THEN
   TBD();
  END;
  RETURN ListPOP(LST,POSN);
 END;

 EXPORT PypopLast(LST)
 //Python analogue
 //Py :Pop item (Posn Omit:Last)
 //PPL:Twofunctions
 BEGIN
  RETURN ListPOPLAST(LST);
 END;

 EXPORT Pyremove(LST,ITEM)
 //Python analogue
 //ALSO NOTE remove in CAS
 //Py :Remove 1st ITEM,ERR IF NONE
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  IF POSN THEN
   RETURN ListREMOVEX(LST,POSN);
  END;
  //ELSE NOTHING TO REMOVE
  RAISE(MN+"Pyremove",EL,ItemNotFoundError,ITEM,PyErrK);
  RETURN LST;
 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)==DOM_FLOAT-1 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(1):="21. ListREMOVEDUPLICATES";
  LST(2):="31. ListOCCURRENCESWITHSORT";
  LST(3):="32. ListGETLIST";
  LST(4):="40. ListREMOVEITEM";
  LST(5):="41. ListCumSum";
  CHOOSE(VR,MN+"Puzzles (See thread)",LST);
 END;

 EXPORT ListPythonAnalogues ()
 BEGIN
  LOCAL KK;
  LOCAL PyFuns:={
   "append item",
   "clear list",
   "copy list",
   "count item instances",
   "extend list by list2",
   "index item in list",
   "insert item before posn",
   "pop item at posn from list",
   "poplast",
   "remove instance of item",
   "reverse list",
   "sort list"};
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,MN+"Py...",PyFuns)

 END;

EXPORT ListSeeAlso ()
 BEGIN
  LOCAL KK;
  LOCAL CatFuns:={
   "append:slower",
   "count",
   "DIFFERENCE",
   "head-slower",
   "intersect-fast(AND)",
   "list2mat",
   "mat2list",
   "prepend",
   "quantile",
   "quartile1",
   "quartile3",
   "quartiles",
   "remove",
   "replace",
   "REVERSE",
   "revlist-slower",
   "suppress",
   "tail:slower",
   "union"};
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,MN+" Relevant Cat Functions",CatFuns)

 END;

 
 EXPORT ListExamples()
 //In real use, use XXX:=List...()
 BEGIN
  LOCAL LL:={1,2,3,4,5,6,7,8,9};
  PRINT();
  PRINT(ListVERSION);
  PRINT("A");
  //PRINT(ListAFTER(LL,2));
  //PRINT(ListANDBOOL({1,12},{0,1},"122"));
  //PRINT(ListANDBOOL({"AA","BB"},{0,1},"CHAR(0)"));
  PRINT("B");
  //PRINT(ListBEFORE(LL,2));
  PRINT("C");
  PRINT(ListCOUNT({},2));
  PRINT(ListCOUNTANYDUPLICATES_SORTED({}));
  PRINT(ListCOUNTANYDUPLICATES({0,2,2,2}));
  PRINT(ListCOUNTITEMS(LL,{2,3}));
  PRINT("D");
  PRINT(ListDIFFER2(LL,CONCAT(LL,2)));
  PRINT("F");
  PRINT(ListFIND(LL,2));
  PRINT("G");
  PRINT(ListGETLIST(LL,{5,3}));
  PRINT("HI");
  PRINT(ListHEAD(LL));
  PRINT(ListINDEX(LL,2));
  PRINT(ListINSERT(LL,2,4));
  PRINT("Is");
  PRINT(ListIsLIST(5));
  PRINT(ListIsNUMERIC({1,2,#3}));
  PRINT(ListIsSET(LL));
  PRINT(ListIsSORTABLE(LL));
  PRINT(ListIsSORTED(LL)); 
  PRINT(ListIsTYPE({3.4},1-1));
  PRINT("MNO");
  PRINT(ListMASKBOOL({1,12},{0,1},"122"));
  PRINT(ListMASKBOOL({"AA","BB"},{0,1},"CHAR(0)"));
  PRINT(ListOCCURRENCES(LL));
  PRINT("P");
  PRINT(ListPOP(LL,2));LL:=ListANS;
  PRINT(ListPOPLAST(LL));LL:=ListANS;
  PRINT("R");
  PRINT(ListREMOVEX(LL,2));
  PRINT(ListREMOVE(LL,9));
  PRINT("S");
  PRINT(ListSHUFFLE(−52));
  PRINT(ListSHUFFLE(52));
  PRINT(ListSHUFFLE({"R","G","B"}));
  PRINT(ListSLICE({1,2,3,4},2,3));
  PRINT(ListSORT(LL));
  PRINT("T");
  PRINT(ListTAIL(LL));
  PRINT(ListToSET({1,2,2}));
  PRINT("STATS");
  PRINT(ListMEDIAN(LL));
  PRINT(ListMODE({"AC","DC"})); 
 
  PRINT("Exampled");
  //RETURN 0; 
 END;

 //These alternative implements are slower:
 //They can be removed but may be useful for testing
 EXPORT Listcountanyduplicates_(LST)
 //SLOWER
 BEGIN
  LOCAL LL:=UNION(LST);
  RETURN (SIZE(LST)-SIZE(LL));
 END;

 EXPORT LIST()
 BEGIN
  ABOUT();
  //ListExamples();
 END;
Indexing of the Python analogues now no longer handles Index 0 in a Python manner. Indexing is now as in PPL. This should therefore be compatible with the Python syntax reported to be in the new Beta release, although I have been unable to test that myself.

Update: This version does not compile.
A couple of missing names - ListCOUNT should be ListCOUNTITEMS and ListDIFFER2 is renamed.

Stephen Lewkowicz (G1CMZ)
Visit this user's website Find all posts by this user
Quote this message in a reply
09-08-2018, 09:50 PM (This post was last modified: 09-08-2018 09:58 PM by StephenG1CMZ.)
Post: #6
RE: List API (G1CMZ): List Processing API
Version 1.3 is a quick mod to those names so that this will compile.

Code:

 LOCAL CRID:="List API V1.3 © 2018 StephenG1CMZ";
 LOCAL MORETEXT:="A collection of list routines brought to you by StephenG1CMZ,\n with some from the forum.";
 
 //Customise
 EXPORT ListShowErrors:=1;//SHOW ERRORS
 EXPORT ListNumericTypes:={DOM_FLOAT-1,DOM_INT-1,DOM_COMPLEX-1,DOM_MATRIX-1};
 //Query: Include COMPLEX,LONGFLOAT,MATRIX?
 EXPORT ListSortableTypes:={DOM_FLOAT-1,DOM_INT-1,3-1};//3-1=MAGIC NUMBER FOR STRINGS NOT DOM_STRING=12 NOT COMPLEX MATRIX OR LIST
  //NB To test: sort >1 item
 //End

 //Forward
 ListCOUNTANYDUPLICATES_SORTED(SORTEDLST);
 ListCOUNTITEM(LST,ITEM);
 ListCOUNTITEMS(LST,ITEMS);
 ListIsTYPE(LST,TYPES);
 ListOCCURRENCES(LST);
 ListREMOVEDUPLICATES(LST);
 ListREMOVEX(LST,POSN);
 ListSORT(LST);
 ListSORTN(LST,NN);

 //NB In main routines (ie not Python)
 //POSN parameter is >=0 (0=LAST)
 //POSN returned is ≥0 (PPL,0=NOTIN)

 //LOCAL SL:=1;
 LOCAL NL:="\n";

 LOCAL MN:="List.";//Name

//TO REFER TO ListTYPE, USE DOM_LIST-1; MAGIC NUMBER FOR LISTS.

 LOCAL ListANS;//OUTPUT LIST(WHEN NOT RETURNED)
  //Also, useful temporary results 

 //ERR 
 LOCAL ListErrK:=1;
 LOCAL PyErrK:=3;
 EXPORT ListLastError:=0;
 LOCAL ERRKIND:={"","Error","","Py Error"};
 //FIX
 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 ListSortError:=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)
 //Only exported for testing
 BEGIN
  LOCAL PROGML:=Programs();
  LOCAL PROGM:=PROGML(1);//NB:THE USER PROGM RUNNING, NOT THAT RAISING THE ERROR :(
  IF ListShowErrors AND SEVERITY>0 THEN
   MSGBOX(PROGM+":"+MN+" "+ERRKIND(SEVERITY+1)+NL+ERRLST(ERR)+NL+CULPRIT);
  END;
  ListLastError:=ERR;
 END;

 //MAINLY STANDARD FUNCTIONS
 //Lowercase names are well defined (described in Wikipedia or Python Docs)
 //UPPERCASE and CamelCase names are more likely to change

 EXPORT ListAFTER(LST,POSN)
 //Slice After POSN:
 //POSN=0 OR LAST:{}
 BEGIN
  LOCAL FRM:=POSN+1;
  RETURN IFTE((POSN==0 OR FRM>SIZE(LST)),{},LST({FRM,SIZE(LST)}));
 END;

 EXPORT ListANDBOOL(LST,LSTBOOL,NewValue)
 //Replace items ANDed out with NULL(NewValue)
 //EG ({"AA","BB"},{0,1},"CHAR(0)") = {"","BB"}//Note the quotes
 //EG ({11,13},{0,1},"12")//NOMORETHAN12
 //RequirementSpec:
 //http://www.hpmuseum.org/forum/thread-5092.html
 //Usage:
 //http://www.hpmuseum.org/forum/thread-5031.html
 //See also:MaskBOOL
 //NULL=NULL
 BEGIN
  //Guard against empty "" giving syn err
  LOCAL MYNULL:=IFTE(NewValue=="","CHAR(0)",NewValue);
  IF SIZE(LST) AND SIZE(LSTBOOL) THEN
   RETURN EXECON("IFTE(&2,&1,"+MYNULL+")",LST,LSTBOOL);
  END;
  RETURN {};
 END;

 
 EXPORT ListBEFORE(LST,POSN)
 //Slice Before POSN: 
 //POSN=0: ({1,2},0)={1}
 BEGIN
  LOCAL TOO:=POSN-1;
  IF POSN==0 THEN
    RETURN ListBEFORE(LST,SIZE(LST));
  END;
  RETURN IFTE(TOO>0,LST({1,TOO}),{});
 END;

 EXPORT ListCONCAT(LST1,LST2)
 //CONCATENATE:BUILTIN
 BEGIN
  CONCAT(LST1,LST2);
 END;

 EXPORT ListCOUNTANYDUPLICATES (LST)
 //Preferred-SORTED
 BEGIN
  ListANS:=ListSORT(LST);
  RETURN ListCOUNTANYDUPLICATES_SORTED(ListANS);
 END;

 EXPORT ListCOUNTANYDUPLICATES_SLOW(LST)
 //Caution can be much slower but may be faster
 //REAL LST NO DUPS:5s 
 //INT LST 8000 DUPS:0.2s
 BEGIN
  RETURN SIZE(LST)-SIZE(ListREMOVEDUPLICATES(LST));
 END;

 EXPORT ListCOUNTANYDUPLICATES_SORTED(SortedLST)
 //Count how many duplicates in a sortedlist,Return a REAL INT
 //({1,9,9}=1 dup, {1,2,2,3,3,3}=3 dup)
 //Timings consistent 0.3s
 BEGIN
  LOCAL II;
  LOCAL DUPCOUNT:=0;
  IF SIZE(SortedLST)>1 THEN
   FOR II FROM 1 TO SIZE(SortedLST)-1 DO
    IF SortedLST(II) ==SortedLST(II+1) THEN
     DUPCOUNT:=DUPCOUNT+1;
    END;//IF
   END;//FOR
   //ELSE:SMALL LISTS HAVE NO DUPLICATES
  END;//IF
  RETURN DUPCOUNT;
 END;

 EXPORT ListCOUNTITEMS(LST,ITEMS)
 //ITEMS MAY BE 1 ITEM OR A LIST OF SEPARATE ITEMS
 //SO TO COUNT LISTS, CONTAIN THEM IN A LIST
 //EG {1,{},2},{{}}= 1
 //EG {1,2,3},{2,3} = 2
 //EG {1,{2,3}},{2,3} = 0 (TO SEARCH FOR ITEM {2,3} USE COUNT)
 //ITEMS NULL=0
 //LST NULL=0
 BEGIN
  RETURN SIZE(INTERSECT(LST,ITEMS));
 END;

 EXPORT ListCSV2LIST()
 //Importing the procedure would introduce a dependency(later?)
 BEGIN
  MSGBOX("To parse CSV files/strings to lists use StephenG1CMZ's CSV program.\n")
 END;

 EXPORT ListDIFFER(LST1,LST2)
 //POSITION OF 1st DIFFERENCE
 //FLOAT≠INTEGER
 //SIZE≠SIZE: SZ+1 RETURNED(UNLESS EARLIER DIFFERENCE)
 BEGIN
  LOCAL II:=1;
  LOCAL SZ:=MIN(SIZE(LST1),SIZE(LST2));

  IF EQ(LST1,LST2) THEN
   RETURN 0;
  END;
  //IF SIZE(LST1)≠SIZE(LST2) THEN
  // RETURN −1;
  //END;
  WHILE II≤SZ DO
   IF TYPE(LST1)≠TYPE(LST2) OR LST1(II)≠LST2(II) THEN
    RETURN II;
   END;
   II:=II+1;
  END; 
  RETURN IFTE(SIZE(LST1)>SZ OR SIZE(LST2)>SZ,SZ+1,0);
 END;

 EXPORT ListFIND(LST,ITEM)
  //See http://www.hpmuseum.org/forum/thread-9431.html
 BEGIN 
  LOCAL X,Y;
  LOCAL LSTPOSNS={};

  WHILE X:=POS(LST,ITEM) DO
    LSTPOSNS(0):=(Y:=X+Y);
    LST:=LST({X,SIZE(LST)}+1)
  END;
  RETURN LSTPOSNS;
 END;
 
 EXPORT ListGETLIST(LST,GETLST)
 //Solves Puzzle #32. POSN≥0.
 //POSN>SIZE(LST):EXCEPTION. RETURN {} FOR THAT ITEM
 BEGIN
 LOCAL II;

  IF SIZE(GETLST) THEN
   IF MAX(GETLST)>SIZE(LST) THEN
    RAISE(MN+"ListGETLIST",EL,IndexOutOfBoundsException,MAX(GETLST)+">"+SIZE(LST),ListErrK);
   END;
   //IFTE GUARDS INDEX>SIZE(LST)
   RETURN MAKELIST(IFTE(GETLST(II)>SIZE(LST),{},LST(GETLST(II))),II,1,SIZE(GETLST));
  END;
  RETURN {};//ASKED TO GET NOTHING
 END;

 EXPORT ListHEAD(LST)
 //List HEAD AKA LISP CAR
 //NULL:ERR
 //PPL FASTER
 //See also:head()
 BEGIN
  IF SIZE(LST) THEN
   RETURN LST(1);
  END;
  RAISE(MN+"ListHEAD",EL,ListIsEmptyError,"",ListErrK);
  RETURN {};
 END;

 EXPORT ListINDEX(LST,ITEM)
 //Despite the confusing name
 //Simple: Return posn of 1st instance of item
 //If you do want to index ITEM, use FIND.
 //NULL: 0
 BEGIN
  RETURN POS(LST,ITEM);
 END;


 EXPORT ListINSERT(LST,POSN,ITEM)
 //INSERT ITEM BEFORE POSN
 //PPL POSN=0 = APPEND
 //Py  POSN=0 = 1ST
 BEGIN
  LOCAL POSNB:=POSN-1;
  LOCAL LSTB:=IFTE(POSN==1,{},LST({1,POSNB}));
  LOCAL LSTA:=LST({POSN,SIZE(LST)});

  IF POSN==0 THEN //IN PPL:
   //IT IS UNCLEAR WHETHER THIS SHOULD APPEND,
   //OR INSERT BEFORE LAST 
   //OPINIONS?
   //TBD();
   RETURN CONCAT(LST,ITEM);
  END;
  RETURN CONCAT(CONCAT(LSTB,ITEM),LSTA);
 END;

 //Query:
 //IsLIST asks-Is parameter this
 //IsNUMERIC,IsSET,IsSORTABLE,IsTYPE ask:Are contents this
 //Change names to clarify?

 EXPORT ListIsLIST(LST)
 //BOOL:Is actual parameter a list_type
 //In PPL lists and sets both 1
 //To check instead that a list contains only lists,
 //use IsTYPE(LST,{DOM_LIST})
 BEGIN
   RETURN (TYPE(LST)==DOM_LIST-1);
 END;

 EXPORT ListIsNUMERIC(LST)
 //Is list currently numeric
 BEGIN 
  RETURN ListIsTYPE(LST,ListNumericTypes);
 END;

 EXPORT ListIsSET(LST)
 //BOOL:Is LST currently a set (no duplicates)
 //A uniquelist (no duplicates) may be a set
 //NULL:1
 BEGIN
  RETURN NOT(ListCOUNTANYDUPLICATES(LST));
 END;

 EXPORT ListIsSORTABLE(LST)
 //0.Is parameter a list
 //1.Is TYPE of contents OF ORDERABLE DATA
 //2.Is ListSORT 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

 BEGIN
  IF TYPE(LST)==DOM_LIST-1 THEN
   RETURN ListIsTYPE(LST,ListSortableTypes);
  END;
  RETURN 0;//NO LIST:CANNOT BE SORTED
 END;

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

 EXPORT ListIsTYPE(LST,TYPES)
 //TYPES: TYPE OR LIST OF TYPES
 //SEE ALSO:IsNUMERIC
 //MAKELIST IS FASTER THAN [FOR,INCREMENT COUNT] 
 BEGIN
  LOCAL II;

  IF TYPE(TYPES)==DOM_FLOAT-1 THEN RETURN ListIsTYPE(LST,{TYPES});
  END;
 
  IF SIZE(LST) AND SIZE(TYPES) THEN
   ListANS:=MAKELIST(IFTE(POS(TYPES,TYPE(LST(II))),1,0),II,1,SIZE(LST));//List matching types
   RETURN IFTE(ΣLIST(ListANS)==SIZE(LST),1,0); //Count them
  END;
  RAISE(MN+"ListIsTYPE",EL,ListIsEmptyError,"",1);
  //EMPTY LST: LST ALWAYS INDETERMINATE (GUARD) 
  //EMPTY TYPES: 0>NO MATCHES OR 1>NO REJECTS 
  RETURN 0;//INDETERMINATE
 END;

 EXPORT ListMASKBOOL(LST,LSTBOOL,NewValue)
 //Mask selected values
 //Cf ANDBOOL
 //Here 1 selects replace, not 0
 //NULL=NULL
 BEGIN 
  //Guard against empty "" giving syn err
  LOCAL MYNULL:=IFTE(NewValue=="","CHAR(0)",NewValue);
  IF SIZE(LST) AND SIZE(LSTBOOL) THEN
   RETURN EXECON("IFTE(&2,"+MYNULL+",&1)",LST,LSTBOOL);
  END;
  RETURN {};
  //Equivalent to
  //RETURN ListANDBOOL(LST,NOT(LSTBOOL),NewValue);
 END;

 EXPORT ListMEANS()
 BEGIN
  MSGBOX("StephenG1CMZ's MEANS program implements several means.");
 END;

 EXPORT ListMEDIAN(LST)
 BEGIN
  IF SIZE(LST) THEN
   RETURN(median(LST));
  END;
  RAISE(MN+"ListMEDIAN",EL,ListIsEmptyError,"",ListErrK);//(NO MEDIAN)
  RETURN {};///
 END;
 //Query:What_error to return?
 //NAN OR {} MIGHT BE THE MEDIAN VALUE
 EXPORT ListMEDIAN2(LSTV,LSTF)
 BEGIN
  IF SIZE(LSTV) AND SIZE(LSTF) THEN
   RETURN(median(LSTV,LSTF));
  END;
  RAISE(MN+"ListMEDIAN2",EL,ListIsEmptyError,"",ListErrK);
  RETURN {};///
 END;

 EXPORT ListMODE(L)
 //From http://www.hpmuseum.org/forum/thread-9393.html
 BEGIN
 LOCAL l1,l2;
 l1:=UNION(L);
 l2:=MAKELIST(SIZE(INTERSECT(L,l1(I))),I,1,SIZE(l1));
 l2:=(l2==MAX(l2))*MAKELIST(I,I,1,SIZE(l1));
 l2:=remove(0,l2);
 MAKELIST(l1(l2(I)),I,1,SIZE(l2));
END;
   
 //MODE1_DEPRECATED is deprecated as it is slower
 //MODE2 is likely slower too,
 //but may be useful as parameters differ
 //(retain for comparisons speed and testing)    

 EXPORT ListMODE2(LSTV,LSTF)
 //Get MODES of ItemXFrequency Lists
 //Empty=Empty
 BEGIN
  LOCAL II;
  LOCAL MODESLST:={};
  LOCAL MODEPOSNS:={};

  IF SIZE(LSTF) AND SIZE(LSTV) THEN
   //Find MODES
   MODEPOSNS:=ListFIND(LSTF,MAX(LSTF));
  
   FOR II FROM 1 TO SIZE(MODEPOSNS) DO
    MODESLST(II):=LSTV(MODEPOSNS(II));
   END;//FOR
  END;//IF
  RETURN MODESLST;
 END;

 EXPORT ListMODE1_DEPRECATED(LST)
 //Get MODES of LST : Empty = Empty
 BEGIN
  //Make uniquelst and count
  ListANS:=ListOCCURRENCES(LST);
  
  RETURN ListMODE2(ListANS(1),ListANS(2));
 END;

 EXPORT ListOCCURRENCES(LST)
 //Given a list
 //Return unique list of occurrences and their occurrence counts as 2 lists
 BEGIN
  LOCAL II;
  LOCAL LSTF:={};
  LOCAL LSTV:=ListREMOVEDUPLICATES(LST);

  FOR II FROM 1 TO SIZE(LSTV) DO
   LSTF(II):=ListCOUNTITEMS(LST,LSTV(II));//FIXED
  END;
  RETURN {LSTV,LSTF};
 END;

 EXPORT ListOCCURRENCESWITHSORT(LST)
 //As OCCURRENCES but the LSTV output is sorted
 //Puzzle #31
 //This trivial implement is quicker than sorting output lists using SORTN
 //(but using SORTN makes selecting sorting by list2 easier)
 //See also: ListSORTBYOCCURRENCES
 BEGIN
  RETURN ListOCCURRENCES(ListSORT(LST));
 END;

//There must be a better name
 EXPORT ListInvOCCUR(LSTV,LSTF)
 //INVERSE OF OCCURRENCES
 //Given V and F yield V,F times
 //NULL=NULL
 //In an OCCURRENCES list V is unique and F>0
 //But We handle V with F=0 and V nonunique
 BEGIN
  LOCAL II,JJ;
  LOCAL LST:={};

  FOR II FROM 1 TO SIZE(LSTV) DO
   IF LSTF(II) THEN //V WITH F>0
    LST:=CONCAT(LST,MAKELIST(LSTV(II),JJ,1,LSTF(II)));
   END;
  END;
 
  RETURN LST;
 END;

 EXPORT ListPOP(LST,POSN)
 //POP POSN OFF LIST
 BEGIN
  LOCAL ITEM;
  IF SIZE(LST) THEN
   ITEM:=LST(IFTE(POSN,POSN,SIZE(LST)));//0=>LAST
   ListANS:=ListREMOVEX(LST,POSN);
  ELSE
   RAISE(MN+"ListPOP",EL,ListIsEmptyError,"",ListErrK);
   ITEM:={};
   ListANS:={};
  END;   
  //RETURN POPPED ITEM
  //BUT ALSO SAVE SHORTENED LST
  RETURN ITEM;
 END;

 
 EXPORT ListPOPLAST(LST)
 //POP POSN OFF LIST
 //Py: POP()
 BEGIN
  RETURN ListPOP(LST,SIZE(LST)); 
 END;

 EXPORT ListremoveX(LST,POSN)
 // CAS ALTERNATIVE TO REMOVEX:MAY BE SLOW
 //See 
 //http://www.hpmuseum.org/forum/thread-9406.html and
 //http://www.hpmuseum.org/forum/thread-7987.html?highlight=suppress 
 //NULL=NULL,POSN>SZE=LST
 BEGIN
  IF POSN THEN
   RETURN suppress(LST,POSN);
  END;
  RETURN suppress(LST,SIZE(LST));//0=LAST
 END;

 EXPORT ListREMOVEX(LST,POSN)
 //REMOVE 1 ITEM AT POSN
 //NULL=NULL,POSN>SIZE=LST (NOWT REMOVED)
 BEGIN
  LOCAL LSTB,LSTA;

  IF POSN THEN
   LSTB:=ListBEFORE(LST,POSN);
   LSTA:=ListAFTER (LST,POSN);
   RETURN CONCAT(LSTB,LSTA);
  ELSE
   //PPL: 0=Remove Last Item
   RETURN ListREMOVEX(LST,SIZE(LST));
   //Py: 0=RemoveFirst ie return TAIL
  END;
 END;

 EXPORT ListremoveCAS(LST,ITEM) 
 //CAS version slower
 //NULL=NULL
 BEGIN
  RETURN remove(ITEM,LST);
 END;

 EXPORT ListREMOVE(LST,ITEM)
 //Remove 1 instance of ITEM
 //NULL=NULL 
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  IF POSN THEN
   RETURN ListREMOVEX(LST,POSN);
  END;
  RAISE(MN+"ListREMOVE",EL,ItemNotFoundError,ITEM,0);
  RETURN LST;//NOTHING TO REMOVE
 END;

 EXPORT ListREMOVEDUPLICATES(LST)
 //RESULT WITH DUPLICATES JUST ONCE 
 //Native: Sequence NOT determined but seems same
 //From #21
 BEGIN
  RETURN UNION(LST);
 END;

 EXPORT ListREMOVEITEM(LST,ITEM)
 //ALL INSTANCES.PUZZLE #40.
 BEGIN
  LOCAL II;
  LOCAL FOUND:=ListFIND(LST,ITEM);
  IF SIZE(FOUND) THEN
   ListANS:=LST;
   //Remove from right:earlier posns unchanged
   FOR II FROM SIZE(FOUND) DOWNTO 1 DO
    ListANS:=ListREMOVEX(ListANS,FOUND(II));
   END;
   RETURN ListANS;
  END;//IF
  RETURN LST;//NOTHING REMOVED 
 END;

 //NB replace in CAS is different
 EXPORT ListREPLACE(LST,ITEM,ITEM2)
 //Replace instances of ITEM with ITEM2
 BEGIN
  LOCAL II;
  LOCAL FOUND:=ListFIND(LST,ITEM);
  IF SIZE(FOUND) THEN
   ListANS:=LST;
   FOR II FROM 1  TO SIZE(FOUND)  DO
    ListANS(FOUND(II)):=ITEM2;
   END;
  ELSE
   RETURN LST;
  END;
  RETURN ListANS; 
 END;

 EXPORT ListSHUFFLE(LST_NUM)
 //SHUFFLE NUM: SHUFFLE 1..N INDEXES 
 //SHUFFLE LST: SHUFFLE LST
 //N<0:GUARD:UNSHUFFLED INDEX
 //NULL OR 0 OR >10000: NULL 
 BEGIN
  LOCAL II,NUM;
  IF TYPE(LST_NUM)=DOM_FLOAT-1 THEN
   NUM:=IFTE(LST_NUM>10000,0,LST_NUM);
   IF LST_NUM<0 THEN //GUARD NEGATIVES (AVOID CRASH)
    RETURN MAKELIST(II,II,1,ABS(NUM));//UNSHUFFLED
   END;
  END;
  RETURN mat2list(randperm(LST_NUM));
 END;

 EXPORT ListSLICE(LST,FRM,TOO)
 //RETURN PART OF LIST (AKA SUB)
 //SYNTAX HINT
 //SUGGEST ALSO IMPL (LST,{2,[3]})
 //FRM≤TOO:Bad Inputs={}
 BEGIN
  LOCAL TTOO:=IFTE(TOO==0,SIZE(LST),TOO); //TO 0==LAST
  LOCAL TFRM:=IFTE(FRM==0,SIZE(LST),FRM); //FRM 0==LAST
  //MSGBOX("SLICE "+{FRM,TOO});
  IF TFRM>TTOO THEN
    //RAISE(IndexOutOfBoundsException,FRM,ListErrK);//Maybe a new error
    RETURN {};
  END; 
  RETURN LST({TFRM,TTOO});
 END;

 EXPORT ListSORT(LST)
 //This implementation uses native SORT
 //On old compilers See known bugs 
 //This will not affect MODE other than changing ordering 
 //Native SORT falls over:Use IsSORTABLE to check 1st
 //NOTE TO DEVELOPERS:
 //NB1:Sorting a list of size 1 is trivial, so test using 2to see if a t 
 BEGIN
  IF TYPE(LST)≠DOM_LIST-1 THEN 
   RAISE(MN+"ListSORT",EL,ListSortError,"",ListErrK);
  END;
  RETURN SORT(LST);
 END;

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

 EXPORT ListSORTN(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 ListSORTBYOCCURRENCES(LST)
 //reverse so most popular is 1st and index is approx rank 
 BEGIN
  ListANS:=ListOCCURRENCES(LST);
  RETURN REVERSE(ListSORTBYKEY(ListANS,2));
 END;

 EXPORT ListTAIL(LST)
 //List TAIL AKA LISP CDR
 //NULL:ERR
 //(SOME USE TAIL=LAST NOT TAIL=CDR)
 //PPL FASTER
 //See also:tail
 BEGIN
  IF SIZE(LST) THEN
   RETURN LST({2,SIZE(LST)});
  END;
  RAISE(MN+"ListTAIL",EL,ListIsEmptyError,"",ListErrK);
  RETURN {};
 END;

 EXPORT ListToSET(LST)
 //In addition to making the list like a set
 //wibni we could track those tnat ARE sets
 BEGIN
  RETURN ListREMOVEDUPLICATES(LST);
 END;

 EXPORT ListVERSION()
 BEGIN
  RETURN CRID;
 END;

 // Python names(LC) prefixed Py ()
 // Py  syntax: Lst.append(ITEM) etc 
 // PPL syntax: Lst:=Pyappend(Lst,ITEM)
 // Py indexes from 0 but not yet implemented
 // These names are inspired by Py, 
 // but may never provide exact equivalents.
 
 //Currently,0 and allindexes are PPL-like
 //Thus it achieves compatability with 
 //PPL(0), and CAS-Python:S-Beta (like PPL, supposedly).
 //but not Python

EXPORT Pyappend(LST,ITEM)
 //Python analogue
 //append a single item
 //NB IF List prefix is dropped conflict with CAS.append (CAS.append is slower)
 //NULL LST: {ITEM}
 // (LST,{ITEMLST}) ADDS 1 ITEM (A LST)EG({1},{2,3}={1,{2,3}})
 BEGIN
  RETURN LST(0):=ITEM; 
 END;

 EXPORT Pyclear(LST)
 //Python analogue
 //Py :ALSO DELETES LIST (cf CAS purge)
 BEGIN 
  RETURN {};
 END;

 EXPORT Pycopy(LST)
 //Python analogue
 //Py: A shallow copy PPL: simple copy
 BEGIN
  RETURN LST;
 END;

 EXPORT Pycount (LST,ITEM)
 //Python analogue
 //Count instances of an ITEM:(WHICH MAY BE A LIST=1ITEM)
 //NB do not confuse with CAS.count(Test,Lst)
 BEGIN  
  RETURN ListCOUNTITEMS(LST,{ITEM});
 END;

 EXPORT Pyextend(LST,LST2)
 //Python analogue
 //Py :Concat items in LST2 to LST
 //Query: If listfull, should we add some or none
 //PPL:LST2 may be an item 
 BEGIN
  RETURN CONCAT(LST,LST2);
 END;

 EXPORT Pyindex(LST,ITEM)
 //Python analogue
 //Py :Return index (or ValueErr)

 //TBD START:END LIMIT RANGE SEARCHED WITHOUT CHANGING INDEX
 BEGIN
  LOCAL LX:=ListINDEX(LST,ITEM); 
  IF LX==0 THEN
   RAISE(MN+"Pyindex",EL,ValueError,ITEM,PyErrK);//Py:NotFound => an error
  END;
  RETURN LX; 
 END;

 EXPORT Pyinsert(LST,POSN,ITEM)
 //Python analogue
 //Py :Insert ITEM before POS
 BEGIN
  RETURN ListINSERT(LST,POSN,ITEM); 
 END;

 EXPORT Pypop(LST,POSN)
 //Python analogue
 //Py :Pop item (Posn Omit:Last)
 //PPL:Posn reqd
 BEGIN
  IF POSN==0 THEN
   TBD();
  END;
  RETURN ListPOP(LST,POSN);
 END;

 EXPORT PypopLast(LST)
 //Python analogue
 //Py :Pop item (Posn Omit:Last)
 //PPL:Twofunctions
 BEGIN
  RETURN ListPOPLAST(LST);
 END;

 EXPORT Pyremove(LST,ITEM)
 //Python analogue
 //ALSO NOTE remove in CAS
 //Py :Remove 1st ITEM,ERR IF NONE
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  IF POSN THEN
   RETURN ListREMOVEX(LST,POSN);
  END;
  //ELSE NOTHING TO REMOVE
  RAISE(MN+"Pyremove",EL,ItemNotFoundError,ITEM,PyErrK);
  RETURN LST;
 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)==DOM_FLOAT-1 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(1):="21. ListREMOVEDUPLICATES";
  LST(2):="31. ListOCCURRENCESWITHSORT";
  LST(3):="32. ListGETLIST";
  LST(4):="40. ListREMOVEITEM";
  LST(5):="41. ListCumSum";
  CHOOSE(VR,MN+"Puzzles (See thread)",LST);
 END;

 EXPORT ListPythonAnalogues ()
 BEGIN
  LOCAL KK;
  LOCAL PyFuns:={
   "append item",
   "clear list",
   "copy list",
   "count item instances",
   "extend list by list2",
   "index item in list",
   "insert item before posn",
   "pop item at posn from list",
   "poplast",
   "remove instance of item",
   "reverse list",
   "sort list"};
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,MN+"Py...",PyFuns)

 END;

EXPORT ListSeeAlso ()
 BEGIN
  LOCAL KK;
  LOCAL CatFuns:={
   "append:slower",
   "count",
   "DIFFERENCE",
   "head-slower",
   "intersect-fast(AND)",
   "list2mat",
   "mat2list",
   "prepend",
   "quantile",
   "quartile1",
   "quartile3",
   "quartiles",
   "remove",
   "replace",
   "REVERSE",
   "revlist-slower",
   "suppress",
   "tail:slower",
   "union"};
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,MN+" Relevant Cat Functions",CatFuns)

 END;

 
 EXPORT ListExamples()
 //In real use, use XXX:=List...()
 BEGIN
  LOCAL LL:={1,2,3,4,5,6,7,8,9};
  PRINT();
  PRINT(ListVERSION);
  PRINT("A");
  //PRINT(ListAFTER(LL,2));
  //PRINT(ListANDBOOL({1,12},{0,1},"122"));
  //PRINT(ListANDBOOL({"AA","BB"},{0,1},"CHAR(0)"));
  PRINT("B");
  //PRINT(ListBEFORE(LL,2));
  PRINT("C");
  PRINT(ListCOUNTITEMS({},2));//FIXED
  PRINT(ListCOUNTANYDUPLICATES_SORTED({}));
  PRINT(ListCOUNTANYDUPLICATES({0,2,2,2}));
  PRINT(ListCOUNTITEMS(LL,{2,3}));
  PRINT("D");
  //PRINT(ListDIFFER2(LL,CONCAT(LL,2)));//FIXED
  PRINT("F");
  PRINT(ListFIND(LL,2));
  PRINT("G");
  PRINT(ListGETLIST(LL,{5,3}));
  PRINT("HI");
  PRINT(ListHEAD(LL));
  PRINT(ListINDEX(LL,2));
  PRINT(ListINSERT(LL,2,4));
  PRINT("Is");
  PRINT(ListIsLIST(5));
  PRINT(ListIsNUMERIC({1,2,#3}));
  PRINT(ListIsSET(LL));
  PRINT(ListIsSORTABLE(LL));
  PRINT(ListIsSORTED(LL)); 
  PRINT(ListIsTYPE({3.4},1-1));
  PRINT("MNO");
  PRINT(ListMASKBOOL({1,12},{0,1},"122"));
  PRINT(ListMASKBOOL({"AA","BB"},{0,1},"CHAR(0)"));
  PRINT(ListOCCURRENCES(LL));
  PRINT("P");
  PRINT(ListPOP(LL,2));LL:=ListANS;
  PRINT(ListPOPLAST(LL));LL:=ListANS;
  PRINT("R");
  PRINT(ListREMOVEX(LL,2));
  PRINT(ListREMOVE(LL,9));
  PRINT("S");
  PRINT(ListSHUFFLE(−52));
  PRINT(ListSHUFFLE(52));
  PRINT(ListSHUFFLE({"R","G","B"}));
  PRINT(ListSLICE({1,2,3,4},2,3));
  PRINT(ListSORT(LL));
  PRINT("T");
  PRINT(ListTAIL(LL));
  PRINT(ListToSET({1,2,2}));
  PRINT("STATS");
  PRINT(ListMEDIAN(LL));
  PRINT(ListMODE({"AC","DC"})); 
 
  PRINT("Exampled");
  //RETURN 0; 
 END;

 //These alternative implements are slower:
 //They can be removed but may be useful for testing
 EXPORT Listcountanyduplicates_(LST)
 //SLOWER
 BEGIN
  LOCAL LL:=UNION(LST);
  RETURN (SIZE(LST)-SIZE(LL));
 END;

 EXPORT LIST()
 BEGIN
  ABOUT();
  //ListExamples();
 END;

Sort routines contained herein have been moved to my Sorts program and will be removed from here soon.

Stephen Lewkowicz (G1CMZ)
Visit this user's website Find all posts by this user
Quote this message in a reply
09-12-2018, 09:17 PM (This post was last modified: 09-12-2018 09:21 PM by StephenG1CMZ.)
Post: #7
RE: List API (G1CMZ): List Processing API
Version 1.4 moves most SORT and REVERSE functions to my Sort API program, and includes some minor changes. (Some List puzzles using sorts remain here, though).

Code:



 LOCAL CRID:="List API V1.4 © 2018 StephenG1CMZ";
 LOCAL MORETEXT:="A collection of list routines brought to you by StephenG1CMZ,\n with some from the forum.";
 LOCAL MN:="List.";//Name

 //Customise
 EXPORT ListShowErrors:=1;//SHOW ERRORS
 EXPORT ListNumericTypes:={DOM_FLOAT-1,DOM_INT-1,DOM_COMPLEX-1,DOM_MATRIX-1};
 //Query: Include COMPLEX,LONGFLOAT,MATRIX?
 //End

 //Forward
 ListCOUNTANYDUPLICATES_SORTED(SORTEDLST);
 ListCOUNTITEM(LST,ITEM);
 ListCOUNTITEMS(LST,ITEMS);
 ListIsTYPE(LST,TYPES);
 ListREMOVEDUPLICATES(LST);
 ListREMOVEX(LST,POSN);
 ListSORT(LST);

 //NB In main routines (ie not Python)
 //POSN parameter is >=0 (0=LAST)
 //POSN returned is ≥0 (PPL,0=NOTFOUND)

 //LOCAL SL:=1;
 LOCAL NL:="\n";

//TO REFER TO ListTYPE, USE DOM_LIST-1; MAGIC NUMBER FOR LISTS.

 LOCAL ListANS;//OUTPUT LIST(WHEN NOT RETURNED)
  //Also, useful temporary results 

 //ERR 
 LOCAL ListErrK:=1;
 LOCAL PyErrK:=3;
 EXPORT ListLastError:=0;
 LOCAL ERRKIND:={"","Error","","Py Error"};
 //FIX
 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 ListSortError:=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)
 //Only exported for testing
 BEGIN
  LOCAL PROGML:=Programs();
  LOCAL PROGM:=PROGML(1);//NB:THE USER PROGM RUNNING, NOT THAT RAISING THE ERROR :(
  IF ListShowErrors AND SEVERITY>0 THEN
   MSGBOX(PROGM+":"+MN+" "+ERRKIND(SEVERITY+1)+NL+ERRLST(ERR)+NL+CULPRIT);
  END;
  ListLastError:=ERR;
 END;

 //Lowercase names are well defined (described in Wikipedia or Python Docs)
 //UPPERCASE and CamelCase names are more likely to change

 EXPORT ListAFTER(LST,POSN)
 //Slice After POSN:
 //POSN=0 OR LAST:{}
 BEGIN
  LOCAL FRM:=POSN+1;
  RETURN IFTE((POSN==0 OR FRM>SIZE(LST)),{},LST({FRM,SIZE(LST)}));
 END;

 EXPORT ListANDBOOL(LST,LSTBOOL,NewValue)
 //Replace items ANDed out with NULL(NewValue)
 //EG ({"AA","BB"},{0,1},"CHAR(0)") = {"","BB"}//Note the quotes
 //EG ({11,13},{0,1},"12")//NOMORETHAN12
 //RequirementSpec:
 //http://www.hpmuseum.org/forum/thread-5092.html
 //Usage:
 //http://www.hpmuseum.org/forum/thread-5031.html
 //See also:MaskBOOL
 //NULL=NULL
 BEGIN
  //Guard against empty "" giving syn err
  LOCAL MYNULL:=IFTE(NewValue=="","CHAR(0)",NewValue);
  IF SIZE(LST) AND SIZE(LSTBOOL) THEN
   RETURN EXECON("IFTE(&2,&1,"+MYNULL+")",LST,LSTBOOL);
  END;
  RETURN {};
 END;

 EXPORT ListBEFORE(LST,POSN)
 //Slice Before POSN: 
 //POSN=0: ({1,2},0)={1}
 BEGIN
  LOCAL TOO:=POSN-1;
  IF POSN==0 THEN
    RETURN ListBEFORE(LST,SIZE(LST));
  END;
  RETURN IFTE(TOO>0,LST({1,TOO}),{});
 END;

 EXPORT ListCONCAT(LST1,LST2)
 //CONCATENATE:BUILTIN
 BEGIN
  CONCAT(LST1,LST2);
 END;

 EXPORT ListCOUNTANYDUPLICATES (LST)
 //Preferred-SORTED
 BEGIN
  ListANS:=ListSORT(LST);
  RETURN ListCOUNTANYDUPLICATES_SORTED(ListANS);
 END;

 EXPORT ListCOUNTANYDUPLICATES_SLOW(LST)
 //Caution can be much slower but may be faster
 //REAL LST NO DUPS:5s 
 //INT LST 8000 DUPS:0.2s
 BEGIN
  RETURN SIZE(LST)-SIZE(ListREMOVEDUPLICATES(LST));
 END;

 EXPORT ListCOUNTANYDUPLICATES_SORTED(SortedLST)
 //Count how many duplicates in a sortedlist,Return a REAL INT
 //({1,9,9}=1 dup, {1,2,2,3,3,3}=3 dup)
 //Timings consistent 0.3s
 BEGIN
  LOCAL II;
  LOCAL DUPCOUNT:=0;
  IF SIZE(SortedLST)>1 THEN
   FOR II FROM 1 TO SIZE(SortedLST)-1 DO
    IF SortedLST(II) ==SortedLST(II+1) THEN
     DUPCOUNT:=DUPCOUNT+1;
    END;//IF
   END;//FOR
   //ELSE:SMALL LISTS HAVE NO DUPLICATES
  END;//IF
  RETURN DUPCOUNT;
 END;

 EXPORT ListCOUNTITEMS(LST,ITEMS)
 //ITEMS MAY BE 1 ITEM OR A LIST OF SEPARATE ITEMS
 //SO TO COUNT LISTS, CONTAIN THEM IN A LIST
 //EG {1,{},2},{{}}= 1
 //EG {1,2,3},{2,3} = 2
 //EG {1,{2,3}},{2,3} = 0 (TO SEARCH FOR ITEM {2,3} USE COUNT)
 //ITEMS NULL=0
 //LST NULL=0
 BEGIN
  RETURN SIZE(INTERSECT(LST,ITEMS));
 END;

 EXPORT ListCOUNTS(LST)
 //Given a list
 //Return unique list of occurrences and their occurrence counts as 2 lists
 //to undo: UNCOUNTS(COUNT())
 BEGIN
  LOCAL II;
  LOCAL LSTF:={};
  LOCAL LSTV:=ListREMOVEDUPLICATES(LST);

  FOR II FROM 1 TO SIZE(LSTV) DO
   LSTF(II):=ListCOUNTITEMS(LST,LSTV(II));//FIXED
  END;
  RETURN {LSTV,LSTF};
 END;

 EXPORT ListCOUNTSWITHSORT(LST)
 //As COUNTS but the LSTV output is sorted
 //Puzzle #31
 //This trivial implement is quicker than sorting output lists using SORTN
 //(but using SORTN makes selecting sorting by list2 easier)
 //See also: ListSORTBYOCCURRENCES
 BEGIN
  RETURN ListCOUNTS(ListSORT(LST));
 END;

 EXPORT ListCSV2LIST()
 //Importing the procedure would introduce a dependency(later?)
 BEGIN
  MSGBOX("To parse CSV files/strings to lists use StephenG1CMZ's CSV program.\n")
 END;

 EXPORT ListDIFFER(LST1,LST2)
 //POSITION OF 1st DIFFERENCE
 //FLOAT≠INTEGER
 //SIZE≠SIZE: SZ+1 RETURNED(UNLESS EARLIER DIFFERENCE)
 BEGIN
  LOCAL II:=1;
  LOCAL SZ:=MIN(SIZE(LST1),SIZE(LST2));

  IF EQ(LST1,LST2) THEN
   RETURN 0;
  END;
  //IF SIZE(LST1)≠SIZE(LST2) THEN
  // RETURN −1;
  //END;
  WHILE II≤SZ DO
   IF TYPE(LST1)≠TYPE(LST2) OR LST1(II)≠LST2(II) THEN
    RETURN II;
   END;
   II:=II+1;
  END; 
  RETURN IFTE(SIZE(LST1)>SZ OR SIZE(LST2)>SZ,SZ+1,0);
 END;

 EXPORT ListFIND(LST,ITEM)
 //Find positions of ITEM in LST
 //See http://www.hpmuseum.org/forum/thread-9431.html
 BEGIN 
  LOCAL X,Y;
  LOCAL LSTPOSNS={};

  WHILE X:=POS(LST,ITEM) DO
    LSTPOSNS(0):=(Y:=X+Y);
    LST:=LST({X,SIZE(LST)}+1)
  END;
  RETURN LSTPOSNS;
 END;
 
 EXPORT ListGETLIST(LST,GETLST)
 //Solves Puzzle #32. POSN≥0.
 //POSN>SIZE(LST):EXCEPTION. RETURN {} FOR THAT ITEM
 BEGIN
 LOCAL II;

  IF SIZE(GETLST) THEN
   IF MAX(GETLST)>SIZE(LST) THEN
    RAISE(MN+"ListGETLIST",EL,IndexOutOfBoundsException,MAX(GETLST)+">"+SIZE(LST),ListErrK);
   END;
   //IFTE GUARDS INDEX>SIZE(LST)
   RETURN MAKELIST(IFTE(GETLST(II)>SIZE(LST),{},LST(GETLST(II))),II,1,SIZE(GETLST));
  END;
  RETURN {};//ASKED TO GET NOTHING
 END;

 EXPORT ListHEAD(LST)
 //List HEAD AKA LISP CAR
 //NULL:ERR
 //PPL FASTER
 //See also:head()
 BEGIN
  IF SIZE(LST) THEN
   RETURN LST(1);
  END;
  RAISE(MN+"ListHEAD",EL,ListIsEmptyError,"",ListErrK);
  RETURN {};
 END;

 EXPORT ListINDEX(LST,ITEM)
 //Despite the confusing name
 //Simple: Return posn of 1st instance of item
 //If you do want to index ITEM, use FIND.
 //NULL: 0
 BEGIN
  RETURN POS(LST,ITEM);
 END;

 EXPORT ListINSERT(LST,POSN,ITEM)
 //INSERT ITEM BEFORE POSN
 //PPL POSN=0 = APPEND
 //Py  POSN=0 = 1ST
 BEGIN
  LOCAL POSNB:=POSN-1;
  LOCAL LSTB:=IFTE(POSN==1,{},LST({1,POSNB}));
  LOCAL LSTA:=LST({POSN,SIZE(LST)});

  IF POSN==0 THEN //IN PPL:
   //IT IS UNCLEAR WHETHER THIS SHOULD APPEND,
   //OR INSERT BEFORE LAST 
   //OPINIONS?
   //TBD();
   RETURN CONCAT(LST,ITEM);
  END;
  RETURN CONCAT(CONCAT(LSTB,ITEM),LSTA);
 END;

 //Query:
 //IsLIST asks-Is parameter this
 //IsNUMERIC,IsSET,IsSORTABLE,IsTYPE ask:Are contents this
 //Change names to clarify?

 EXPORT ListIsLIST(LST)
 //BOOL:Is actual parameter a list_type
 //In PPL lists and sets both 1
 //To check instead that a list contains only lists,
 //use IsTYPE(LST,{DOM_LIST})
 BEGIN
   RETURN (TYPE(LST)==DOM_LIST-1);
 END;

 EXPORT ListIsNUMERIC(LST)
 //Is list currently numeric
 BEGIN 
  RETURN ListIsTYPE(LST,ListNumericTypes);
 END;

 EXPORT ListIsSET(LST)
 //BOOL:Is LST currently a set (no duplicates)
 //A uniquelist (no duplicates) may be a set
 //NULL:1
 BEGIN
  RETURN NOT(ListCOUNTANYDUPLICATES(LST));
 END;

 EXPORT ListIsTYPE(LST,TYPES)
 //TYPES: TYPE OR LIST OF TYPES
 //SEE ALSO:IsNUMERIC
 //MAKELIST IS FASTER THAN [FOR,INCREMENT COUNT] 
 BEGIN
  LOCAL II;

  IF TYPE(TYPES)==DOM_FLOAT-1 THEN RETURN ListIsTYPE(LST,{TYPES});
  END;
 
  IF SIZE(LST) AND SIZE(TYPES) THEN
   ListANS:=MAKELIST(IFTE(POS(TYPES,TYPE(LST(II))),1,0),II,1,SIZE(LST));//List matching types
   RETURN IFTE(ΣLIST(ListANS)==SIZE(LST),1,0); //Count them
  END;
  RAISE(MN+"ListIsTYPE",EL,ListIsEmptyError,"",1);
  //EMPTY LST: LST ALWAYS INDETERMINATE (GUARD) 
  //EMPTY TYPES: 0>NO MATCHES OR 1>NO REJECTS 
  RETURN 0;//INDETERMINATE
 END;

 EXPORT ListMASKBOOL(LST,LSTBOOL,NewValue)
 //Mask selected values
 //Cf ANDBOOL
 //Here 1 selects replace, not 0
 //NULL=NULL
 BEGIN 
  //Guard against empty "" giving syn err
  LOCAL MYNULL:=IFTE(NewValue=="","CHAR(0)",NewValue);
  IF SIZE(LST) AND SIZE(LSTBOOL) THEN
   RETURN EXECON("IFTE(&2,"+MYNULL+",&1)",LST,LSTBOOL);
  END;
  RETURN {};
  //Equivalent to
  //RETURN ListANDBOOL(LST,NOT(LSTBOOL),NewValue);
 END;

 EXPORT ListMEANS()
 BEGIN
  MSGBOX("StephenG1CMZ's MEANS program implements several means.");
 END;

 EXPORT ListMEDIAN(LST)
 BEGIN
  IF SIZE(LST) THEN
   RETURN(median(LST));
  END;
  RAISE(MN+"ListMEDIAN",EL,ListIsEmptyError,"",ListErrK);//(NO MEDIAN)
  RETURN {};///
 END;
 //Query:What_error to return?
 //NAN OR {} MIGHT BE THE MEDIAN VALUE
 EXPORT ListMEDIAN2(LSTV,LSTF)
 BEGIN
  IF SIZE(LSTV) AND SIZE(LSTF) THEN
   RETURN(median(LSTV,LSTF));
  END;
  RAISE(MN+"ListMEDIAN2",EL,ListIsEmptyError,"",ListErrK);
  RETURN {};///
 END;

 EXPORT ListMODE(L)
 //From http://www.hpmuseum.org/forum/thread-9393.html
 BEGIN
 LOCAL l1,l2;
 l1:=UNION(L);
 l2:=MAKELIST(SIZE(INTERSECT(L,l1(I))),I,1,SIZE(l1));
 l2:=(l2==MAX(l2))*MAKELIST(I,I,1,SIZE(l1));
 l2:=remove(0,l2);
 MAKELIST(l1(l2(I)),I,1,SIZE(l2));
END;
   
 //MODE1_DEPRECATED is deprecated as it is slower
 //MODE2 is likely slower too,
 //but may be useful as parameters differ
 //(retain for comparisons speed and testing)    

 EXPORT ListMODE2(LSTV,LSTF)
 //Get MODES of ItemXFrequency Lists
 //Empty=Empty
 BEGIN
  LOCAL II;
  LOCAL MODESLST:={};
  LOCAL MODEPOSNS:={};

  IF SIZE(LSTF) AND SIZE(LSTV) THEN
   //Find MODES
   MODEPOSNS:=ListFIND(LSTF,MAX(LSTF));
  
   FOR II FROM 1 TO SIZE(MODEPOSNS) DO
    MODESLST(II):=LSTV(MODEPOSNS(II));
   END;//FOR
  END;//IF
  RETURN MODESLST;
 END;

 EXPORT ListMODE1_DEPRECATED(LST)
 //Get MODES of LST : Empty = Empty
 BEGIN
  //Make uniquelst and count
  ListANS:=ListCOUNTS(LST);//FIXED
  
  RETURN ListMODE2(ListANS(1),ListANS(2));
 END;

EXPORT ListOCCURRENCES()
BEGIN
  MSGBOX("Renamed: ListCOUNTS...");
END;

 EXPORT ListPOP(LST,POSN)
 //POP POSN OFF LIST
 BEGIN
  LOCAL ITEM;
  IF SIZE(LST) THEN
   ITEM:=LST(IFTE(POSN,POSN,SIZE(LST)));//0=>LAST
   ListANS:=ListREMOVEX(LST,POSN);
  ELSE
   RAISE(MN+"ListPOP",EL,ListIsEmptyError,"",ListErrK);
   ITEM:={};
   ListANS:={};
  END;   
  //RETURN POPPED ITEM
  //BUT ALSO SAVE SHORTENED LST
  RETURN ITEM;
 END;

 EXPORT ListPOPLAST(LST)
 //POP POSN OFF LIST
 //Py: POP()
 BEGIN
  RETURN ListPOP(LST,SIZE(LST)); 
 END;

 EXPORT ListremoveX(LST,POSN)
 // CAS ALTERNATIVE TO REMOVEX:MAY BE SLOW
 //See 
 //http://www.hpmuseum.org/forum/thread-9406.html and
 //http://www.hpmuseum.org/forum/thread-7987.html?highlight=suppress 
 //NULL=NULL,POSN>SZE=LST
 BEGIN
  IF POSN THEN
   RETURN suppress(LST,POSN);
  END;
  RETURN suppress(LST,SIZE(LST));//0=LAST
 END;

 EXPORT ListREMOVEX(LST,POSN)
 //REMOVE 1 ITEM AT POSN
 //NULL=NULL,POSN>SIZE=LST (NOWT REMOVED)
 BEGIN
  LOCAL LSTB,LSTA;

  IF POSN THEN
   LSTB:=ListBEFORE(LST,POSN);
   LSTA:=ListAFTER (LST,POSN);
   RETURN CONCAT(LSTB,LSTA);
  ELSE
   //PPL: 0=Remove Last Item
   RETURN ListREMOVEX(LST,SIZE(LST));
   //Py: 0=RemoveFirst ie return TAIL
  END;
 END;

 EXPORT ListremoveCAS(LST,ITEM) 
 //CAS version slower
 //NULL=NULL
 BEGIN
  RETURN remove(ITEM,LST);
 END;

 EXPORT ListREMOVE(LST,ITEM)
 //Remove 1 instance of ITEM
 //NULL=NULL 
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  IF POSN THEN
   RETURN ListREMOVEX(LST,POSN);
  END;
  RAISE(MN+"ListREMOVE",EL,ItemNotFoundError,ITEM,0);
  RETURN LST;//NOTHING TO REMOVE
 END;

 EXPORT ListREMOVEDUPLICATES(LST)
 //RESULT WITH DUPLICATES JUST ONCE 
 //Native: Sequence NOT determined but seems same
 //From #21
 BEGIN
  RETURN UNION(LST);
 END;

 EXPORT ListREMOVEITEM(LST,ITEM)
 //ALL INSTANCES.PUZZLE #40.
 BEGIN
  LOCAL II;
  LOCAL FOUND:=ListFIND(LST,ITEM);
  IF SIZE(FOUND) THEN
   ListANS:=LST;
   //Remove from right:earlier posns unchanged
   FOR II FROM SIZE(FOUND) DOWNTO 1 DO
    ListANS:=ListREMOVEX(ListANS,FOUND(II));
   END;
   RETURN ListANS;
  END;//IF
  RETURN LST;//NOTHING REMOVED 
 END;

 //NB replace in CAS is different
 EXPORT ListREPLACE(LST,ITEM,ITEM2)
 //Replace instances of ITEM with ITEM2
 BEGIN
  LOCAL II;
  LOCAL FOUND:=ListFIND(LST,ITEM);
  IF SIZE(FOUND) THEN
   ListANS:=LST;
   FOR II FROM 1  TO SIZE(FOUND)  DO
    ListANS(FOUND(II)):=ITEM2;
   END;
  ELSE
   RETURN LST;
  END;
  RETURN ListANS; 
 END;

 EXPORT ListSHUFFLE(LST_NUM)
 //SHUFFLE NUM: SHUFFLE 1..N INDEXES 
 //SHUFFLE LST: SHUFFLE LST
 //N<0:GUARD:UNSHUFFLED INDEX
 //NULL OR 0 OR >10000: NULL 
 BEGIN
  LOCAL II,NUM;
  IF TYPE(LST_NUM)=DOM_FLOAT-1 THEN
   NUM:=IFTE(LST_NUM>10000,0,LST_NUM);
   IF LST_NUM<0 THEN //GUARD NEGATIVES (AVOID CRASH)
    RETURN MAKELIST(II,II,1,ABS(NUM));//UNSHUFFLED
   END;
  END;
  RETURN mat2list(randperm(LST_NUM));
 END;

 EXPORT ListSLICE(LST,FRM,TOO)
 //RETURN PART OF LIST (AKA SUB)
 //SYNTAX HINT
 //SUGGEST ALSO IMPL (LST,{2,[3]})
 //FRM≤TOO:Bad Inputs={}
 BEGIN
  LOCAL TTOO:=IFTE(TOO==0,SIZE(LST),TOO); //TO 0==LAST
  LOCAL TFRM:=IFTE(FRM==0,SIZE(LST),FRM); //FRM 0==LAST
  //MSGBOX("SLICE "+{FRM,TOO});
  IF TFRM>TTOO THEN
    //RAISE(IndexOutOfBoundsException,FRM,ListErrK);//Maybe a new error
    RETURN {};
  END; 
  RETURN LST({TFRM,TTOO});
 END;

 EXPORT ListSORT(LST)
 //This implementation uses native SORT
 //On old compilers See known bugs 
 //This will not affect MODE other than changing ordering 
 //Native SORT falls over:Use IsSORTABLE to check 1st
 //NOTE TO DEVELOPERS:
 //NB1:Sorting a list of size 1 is trivial, so test using 2to see if a t 
 BEGIN
  IF TYPE(LST)≠DOM_LIST-1 THEN 
   RAISE(MN+"ListSORT",EL,ListSortError,"",ListErrK);
  END;
  RETURN SORT(LST);
 END;

 EXPORT ListTAIL(LST)
 //List TAIL AKA LISP CDR
 //NULL:ERR
 //(SOME USE TAIL=LAST NOT TAIL=CDR)
 //PPL FASTER
 //See also:tail
 BEGIN
  IF SIZE(LST) THEN
   RETURN LST({2,SIZE(LST)});
  END;
  RAISE(MN+"ListTAIL",EL,ListIsEmptyError,"",ListErrK);
  RETURN {};
 END;

 EXPORT ListToSET(LST)
 //In addition to making the list like a set
 //wibni we could track those tnat ARE sets
 BEGIN
  RETURN ListREMOVEDUPLICATES(LST);
 END;

 EXPORT ListUNCOUNTS(LSTV,LSTF)
 //INVERSE OF COUNTS. Syntaxes:
 // IsList(LSTF) -> (LSTV,LSTF)
 // ELSE         -> ({LSTV,LSTF},−1) :MATCHES ListCOUNTS
 // NULL         -> NULL
 //Given V and F yield V,F times
 
 //In a COUNTS list V is unique and F>0
 //But We handle V with F=0 and V nonunique too
 BEGIN
  LOCAL II,JJ;
  LOCAL LST:={};
 
  IF TYPE(LSTF)==TYPE({}) THEN
   IF SIZE(LSTV) AND SIZE(LSTF) THEN
    FOR II FROM 1 TO SIZE(LSTV) DO
     //F:0-NOP >0 MAKE (<0 IGNORED , OR COULD RAISE) 
     IF LSTF(II)>0 THEN //V WITH F>0
      LST:=CONCAT(LST,MAKELIST(LSTV(II),JJ,1,LSTF(II)));
     END;
    END;//FOR
   END;
  ELSE //LSTF NOT A LST
   IF SIZE(LSTV)≥2 THEN
    RETURN ListUNCOUNTS(LSTV(1),LSTV(2)); 
   END;
  END;
  RETURN LST;
 END;

 EXPORT ListVERSION()
 BEGIN
  RETURN CRID;
 END;

 // Python names(LC) prefixed Py ()
 // Py  syntax: Lst.append(ITEM) etc 
 // PPL syntax: Lst:=Pyappend(Lst,ITEM)
 // Py indexes from 0 but not yet implemented
 // These names are inspired by Py, 
 // but may never provide exact equivalents.
 
 //Currently,0 and allindexes are PPL-like
 //Thus it achieves compatability with 
 //PPL(0), and CAS-Python:S-Beta (like PPL, supposedly).
 //but not Python

 EXPORT Pyappend(LST,ITEM)
 //Python analogue
 //append a single item
 //NB IF List prefix is dropped conflict with CAS.append (CAS.append is slower)
 //NULL LST: {ITEM}
 // (LST,{ITEMLST}) ADDS 1 ITEM (A LST)EG({1},{2,3}={1,{2,3}})
 BEGIN
  RETURN LST(0):=ITEM; 
 END;

 EXPORT Pyclear(LST)
 //Python analogue
 //Py :ALSO DELETES LIST (cf CAS purge)
 BEGIN 
  RETURN {};
 END;

 EXPORT Pycopy(LST)
 //Python analogue
 //Py: A shallow copy PPL: simple copy
 BEGIN
  RETURN LST;
 END;

 EXPORT Pycount (LST,ITEM)
 //Python analogue
 //Count instances of an ITEM:(WHICH MAY BE A LIST=1ITEM)
 //NB do not confuse with CAS.count(Test,Lst)
 BEGIN  
  RETURN ListCOUNTITEMS(LST,{ITEM});
 END;

 EXPORT Pyextend(LST,LST2)
 //Python analogue
 //Py :Concat items in LST2 to LST
 //Query: If listfull, should we add some or none
 //PPL:LST2 may be an item 
 BEGIN
  RETURN CONCAT(LST,LST2);
 END;

 EXPORT Pyindex(LST,ITEM)
 //Python analogue
 //Py :Return index (or ValueErr)

 //TBD START:END LIMIT RANGE SEARCHED WITHOUT CHANGING INDEX
 BEGIN
  LOCAL LX:=ListINDEX(LST,ITEM); 
  IF LX==0 THEN
   RAISE(MN+"Pyindex",EL,ValueError,ITEM,PyErrK);//Py:NotFound => an error
  END;
  RETURN LX; 
 END;

 EXPORT Pyinsert(LST,POSN,ITEM)
 //Python analogue
 //Py :Insert ITEM before POS
 BEGIN
  RETURN ListINSERT(LST,POSN,ITEM); 
 END;

 EXPORT Pypop(LST,POSN)
 //Python analogue
 //Py :Pop item (Posn Omit:Last)
 //PPL:Posn reqd
 BEGIN
  IF POSN==0 THEN
   TBD();
  END;
  RETURN ListPOP(LST,POSN);
 END;

 EXPORT PypopLast(LST)
 //Python analogue
 //Py :Pop item (Posn Omit:Last)
 //PPL:Twofunctions
 BEGIN
  RETURN ListPOPLAST(LST);
 END;

 EXPORT Pyremove(LST,ITEM)
 //Python analogue
 //ALSO NOTE remove in CAS
 //Py :Remove 1st ITEM,ERR IF NONE
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  IF POSN THEN
   RETURN ListREMOVEX(LST,POSN);
  END;
  //ELSE NOTHING TO REMOVE
  RAISE(MN+"Pyremove",EL,ItemNotFoundError,ITEM,PyErrK);
  RETURN 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(1):="21. ListREMOVEDUPLICATES";
  LST(2):="31. ListCOUNTSWITHSORT";
  LST(3):="32. ListGETLIST";
  LST(4):="40. ListREMOVEITEM";
  LST(5):="41. ListCumSum";
  CHOOSE(VR,MN+"Puzzles (See thread)",LST);
 END;

 EXPORT ListPythonAnalogues ()
 BEGIN
  LOCAL KK;
  LOCAL PyFuns:={
   "append item",
   "clear list",
   "copy list",
   "count item instances",
   "extend list by list2",
   "index item in list",
   "insert item before posn",
   "pop item at posn from list",
   "poplast",
   "remove instance of item"};
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,MN+"Py...",PyFuns)

 END;

EXPORT ListSeeAlso ()
 BEGIN
  LOCAL KK;
  LOCAL CatFuns:={
   "append:slower",
   "count",
   "DIFFERENCE",
   "head-slower",
   "intersect-fast(AND)",
   "list2mat",
   "mat2list",
   "prepend",
   "quantile",
   "quartile1",
   "quartile3",
   "quartiles",
   "remove",
   "replace",
   "suppress",
   "tail:slower",
   "union",
   "&StephenG1CMZ's SORT... program"};
  //Cannot call SORTAPI as List compiles 1st
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,MN+" Relevant Cat Functions",CatFuns)
 END;

 
 EXPORT ListExamples()
 //In real use, use XXX:=List...()
 BEGIN
  LOCAL LL:={1,2,3,4,5,6,7,8,9};
  LOCAL LLL:=CONCAT(LL,LL);
  PRINT();
  PRINT(ListVERSION);
  PRINT("A");
  PRINT(ListAFTER(LL,2));
  PRINT(ListANDBOOL({1,12},{0,1},"122"));
  PRINT(ListANDBOOL({"AA","BB"},{0,1},"CHAR(0)"));
  PRINT("B");
  PRINT(ListBEFORE(LL,2));
  PRINT("C");
  PRINT(ListCONCAT(LL,LL));
  PRINT(ListCOUNTANYDUPLICATES_SLOW({}));
  PRINT(ListCOUNTANYDUPLICATES_SORTED({}));
  PRINT(ListCOUNTANYDUPLICATES({0,2,2,2}));
  PRINT(ListCOUNTITEMS({},2));
  PRINT(ListCOUNTITEMS(LL,{2,3}));
  PRINT(ListCOUNTS(LLL));
  //PRINT(ListUNCOUNTS(ListCOUNTS(LLL)));
  PRINT(ListCOUNTSWITHSORT(LLL));
  PRINT("D"); 
  PRINT(ListDIFFER(LL,LL));
  PRINT(ListDIFFER(LL,CONCAT(LL,2)));
  PRINT("F");
  PRINT(ListFIND(CONCAT(LL,LL),2));
  PRINT("G");
  PRINT(ListGETLIST(LL,{5,3}));
  PRINT("HI");
  PRINT(ListHEAD(LL));
  PRINT(ListINDEX(LL,2));
  PRINT(ListINSERT(LL,2,4));
  PRINT("Is");
  PRINT(ListIsLIST(5));
  PRINT(ListIsNUMERIC({1,2,#3}));
  PRINT(ListIsSET(LL));
  PRINT(ListIsTYPE({3.4},1-1));
  PRINT("MNO");
  PRINT(ListMASKBOOL({1,12},{0,1},"122"));
  PRINT(ListMASKBOOL({"AA","BB"},{0,1},"CHAR(0)"));
  PRINT("P");
  PRINT(ListPOP(LL,2));LL:=ListANS;
  PRINT(ListPOPLAST(LL));LL:=ListANS;
  PRINT("R");
  PRINT(ListREMOVEX(LL,2));
  PRINT(ListREMOVE(LL,9));
  PRINT("S");
  PRINT(ListSHUFFLE(−52));
  PRINT(ListSHUFFLE(52));
  PRINT(ListSHUFFLE({"R","G","B"}));
  PRINT(ListSLICE({1,2,3,4},2,3));
  PRINT(ListSORT(LL));
  PRINT("T");
  PRINT(ListTAIL(LL));
  PRINT(ListToSET({1,2,2}));
  PRINT("STATS");
  PRINT(ListMEDIAN(LL));
  PRINT(ListMODE({"AC","DC"})); 
 
  PRINT("Exampled");
  //RETURN 0; 
 END;

 //These alternative implements are slower:
 //They can be removed but may be useful for testing
 EXPORT Listcountanyduplicates_(LST)
 //SLOWER
 BEGIN
  LOCAL LL:=UNION(LST);
  RETURN (SIZE(LST)-SIZE(LL));
 END;

 EXPORT LIST()
 BEGIN
  ABOUT();
  //ListExamples();
 END;

Stephen Lewkowicz (G1CMZ)
Visit this user's website Find all posts by this user
Quote this message in a reply
09-13-2018, 06:35 PM (This post was last modified: 09-13-2018 06:41 PM by pier4r.)
Post: #8
RE: List API (G1CMZ): List Processing API
Stephen you may receive no feedback on your work (I myself I am not yet using it), but kudos!

Seeing people contributing with not so trivial work (that surely takes tens if not hundred if not thousands of brain hours) that continue to do it even without any visible feedback is amazing. Those actions are real motivating ones! (other users that do it are Gamo with his sparring partner Dieter, then Gerald H, DavidM, Namir, Claudio, JKB, the maintainer of Emu48, Eric, Egan, etc. actually a good 25% of the forum)

Wikis are great, Contribute :)
Find all posts by this user
Quote this message in a reply
09-14-2018, 03:36 PM (This post was last modified: 09-14-2018 03:59 PM by StephenG1CMZ.)
Post: #9
RE: List API (G1CMZ): List Processing API
Pier4r, thank you for your words of encouragement.

I admit it was disappointing when I discovered V1.2 had been released for some time without comment even though it would not compile ( the missing names were accessible in local backups, until I lost them).

But although the collection as a whole has attracted little interest yet, several of the included routines were the subject of threads enquiring how to implement tasks using PPL features, and those were always answered helpfully.

I also drew much inspiration from the list processing and puzzles threads (not aimed at the Prime), which led me to collect together several list procedures, and then compare them with list primitives from Wikipedia and Python to ensure some level of completeness and portability.

The next big task would be to add the many additional list primitives available in Java...
In the meantime, if there are any particular functions I've missed - suggestions are welcome.

Stephen Lewkowicz (G1CMZ)
Visit this user's website Find all posts by this user
Quote this message in a reply
09-14-2018, 05:58 PM (This post was last modified: 09-14-2018 05:58 PM by pier4r.)
Post: #10
RE: List API (G1CMZ): List Processing API
For this putting quality work without receiving feedback is amazing, because persistence makes a huge difference in the long run. It is difficult to be persistent without feedback since we are social animals and we need some.

Nice that the processing list motivated two works. The listext for the 50g (http://www.hpmuseum.org/forum/thread-8555.html) and this one.

Question/suggestion: does your API (I didn't check it much) includes all the (feasible) list commands that DavidM did for his API, and as well those present in goferlist as well?

Wikis are great, Contribute :)
Find all posts by this user
Quote this message in a reply
09-14-2018, 06:55 PM
Post: #11
RE: List API (G1CMZ): List Processing API
1.2 compiled for me. I may have had to fix it to get it to compile, though. See for yourself here:

https://www.hpcalc.org/historical/listapi-1.2.zip
Visit this user's website Find all posts by this user
Quote this message in a reply
09-14-2018, 09:59 PM
Post: #12
RE: List API (G1CMZ): List Processing API
(09-14-2018 06:55 PM)Eric Rechlin Wrote:  1.2 compiled for me. I may have had to fix it to get it to compile, though. See for yourself here:

https://www.hpcalc.org/historical/listapi-1.2.zip

For me it compiled when uploaded, but on downloading it after suffering a file loss it did not.
Presumably, two identifiers were previously defined in a local backup:
A reference to ListCOUNT should have been ListCOUNTITEMS
Print(ListDIFFER2) was commented out in the examples.

Stephen Lewkowicz (G1CMZ)
Visit this user's website Find all posts by this user
Quote this message in a reply
09-14-2018, 10:09 PM
Post: #13
RE: List API (G1CMZ): List Processing API
Pier4r, no ListAPI does not include ListExt or goferlist.

There are some functions that duplicate those in ListExt, such as removing duplicates from lists, but many more in Listext with no equivalent in ListAPI - and I have made no attempt to keep names the same.
I can see that adding some more functions and using consistent names could be useful.

As for goferlist, the .doc files I have found are not readable on my Android.

Stephen Lewkowicz (G1CMZ)
Visit this user's website Find all posts by this user
Quote this message in a reply
09-14-2018, 10:49 PM
Post: #14
RE: List API (G1CMZ): List Processing API
From here https://www.hpcalc.org/details/6529 you get a readme that is a txt.

anyway

Code:


GoferLists 1.0 (SysRPL version) for the HP-49G/49G+/50G
========== === ======= ======== === === ===============

Library Id: 1652

Copyright (c) 1994 by Jarno Peschier (http://www.jarno.demon.nl/hp48.htm)
Copyright (c) 2001 by Luis Morales Boisset (http://www.arrakis.es/~lboisset/)
Copyright (c) 2007 by Albert Graef (http://www.musikwissenschaft.uni-mainz.de/~ag/hp49)

GoferLists is a library of useful list processing functions mostly borrowed
from the Haskell programming language. The name comes from the popular Haskell
dialect and interpreter by Mark P. Jones, which was originally called Gofer
and is now known as Hugs ("Haskell User's Gofer System", see
http://www.haskell.org/hugs/).

RPL's built-in list processing facilities such as DOLIST and STREAM are quite
powerful, but can be awkward to work with because they do not treat the corner
cases such as empty input lists in a consistent fashion. GoferLists attempts
to fix that by providing user-friendly frontends to the built-in operations,
in the form of an elaborate collection of generic list processing functions
which are fairly standard in modern functional languages and have proven their
utility in countless applications. GoferLists is implemented in System RPL and
thus the provided operations are fairly efficient as well.

GoferLists was originally written by Jarno Peschier and later ported to SysRPL
for better performance by Luis Morales Boisset. The present version was put
together by Albert Graef who fixed a couple of minor bugs in the SysRPL
version and added a bunch of additional operations (see the revision history
in the following section for details).

See below for installation instructions and an overview of the functions
provided in this version of the library. Also see README.OLD for the original
documentation included with the 0.1b version. Please report bugs in the
present version to Albert Graef at Dr.Graef@t-online.de.


REVISION HISTORY
======== =======

1.0 Jan 24 2007

Bugfixes and new operations by Albert Graef.

- Head, Tail and Init now produce the appropriate dimension errors on an empty
  list.

- Copy now works with zero repeat count.

- Concat is now implemented in terms of Foldl.

- Nub was reimplemented in terms of ^AppendList instead of a (non-existing)
  lib 776 entry point.

- Foldl, Foldr now take args in reverse order ({} ob prog), to facilitate
  "currying", and now work with empty input lists.

- Subs now works with empty input lists.

- New functions: All, Any, Foldl1, Foldr1, Scanl, Scanr, Scanl1, Scanr1,
  Zip/Unzip and friends, Seq, ElemIndex, Find, FindIndex, Insert, Delete,
  Union/Diff/Intersect, Iterate, While, Until, Chars, Strcat, Sum, Product.
  This makes for a total of 56 operations now, hence the library menu was
  reordered alphabetically, to make it easier to find a particular function.

0.1b (2001)

Ported to System RPL by Luis Morales Boisset.

0.1 (1994)

Original User RPL version by Jarno Peschier (JPSOFT).


INSTALLATION
============

Transfer glsys49.lib to your calculator and store it in port 0, 1 or 2 (e.g.,
2 STO). Do a quick reboot with On+C, or just 1652 ATTACH, in order to attach
the library. After that the GoferLists function should be available via the
LIB menu or using the command 1652 MENU. For quicker access you might wish to
assign \<< 1652 MENU \>> to a key or include it in your custom menu.

IMPORTANT: GoferLists 1.0 is for the HP-49 series only, for the HP-48 series
calculators you'll have to go with the 0.1 UserRPL version still available at
http://www.hpcalc.org. This is BETA SOFTWARE, so please back up your
calculator before trying it! No warranty etc. etc.


OVERVIEW
========

Here is a brief rundown of the available functions. Most functions are named
after their Haskell counterparts (see, e.g., http://haskell.org/hoogle), but
some may take different arguments or take arguments in a different order, see
the notes below. Some functions don't exist in Haskell, but are provided here
for convenience. Other functions might work a bit different from their Haskell
counterparts, but still serve the same purpose.

Symbol legend: 0/1: truth value, s: string; n: integer (zint or real); x, y,
z: any object (sometimes also an arbitrary real or zint); xs, ys, zs: list;
xss, yss, zss: list of list; f: arbitrary program; p: predicate (program which
returns 0/1 to denote a truth value)

Function    Stack Diagram        Example
--------------  ----------------------  ------------------------------------
All        xs p -> 0/1        { 1 2 3 } \<< 0 > \>> All
                    -> 1.
Any        xs p -> 0/1        { 1 2 3 } \<< 0 < \>> Any
                    -> 0.
Chars        s -> xs            "abc" Chars
                    -> { "a" "b" "c" }
Concat        xss -> ys        { { 1 } { 2 3 } } Concat
                    -> { 1 2 3 }
Copy        xs n -> ys        { 1 2 3 } 3 Copy
                    -> { 1 2 3 1 2 3 1 2 3 }
Delete        xs x -> ys        { 1 2 3 } 2 Delete
                    -> { 1 3 }
Diff        xs ys -> zs        { 1 2 3 } { 3 4 5 } Diff
                    -> { 1 2 }
Drop        xs n -> ys        { 1 2 3 } 2 Drop
                    -> { 3 }
DropWhile    xs p -> ys        { 1 2 3 } \<< 2 < \>> DropWhile
                    -> { 2 3 }
Elem        xs x -> 0/1        { 1 2 3 } 2 Elem
                    -> 1.
ElemIndex    xs x -> n        { 1 2 3 } 2 ElemIndex
                    -> 2.
Filter        xs p -> ys        { 1 2 3 } \<< 1 > \>> Filter
                    -> { 2 3 }
Find        xs p -> x        { 1 2 3 } \<< 1 > \>> Find
                    -> 2
FindIndex    xs p -> n        { 1 2 3 } \<< 1 > \>> FindIndex
                    -> 2.
Foldl        xs x f -> ys        { 1 2 3 } 0 \<< + \>> Foldl
                    -> 6
Foldl1        xs f -> ys        { 1 2 3 } \<< + \>> Foldl1
                    -> 6
Foldr        xs x f -> ys        { 1 2 3 } 0 \<< + \>> Foldr
                    -> 6
Foldr1        xs f -> ys        { 1 2 3 } \<< + \>> Foldr1
                    -> 6
Head        xs -> x            { 1 2 3 } Head
                    -> 1
Init        xs -> ys        { 1 2 3 } Init
                    -> { 1 2 }
Inits        xs -> yss        { 1 2 3 } Inits
                    -> { { } { 1 } { 1 2 } { 1 2 3 } }
Insert        xs x -> ys        { 1 2 3 } 4 Insert
                    -> { 1 2 3 4 }
Intersect    xs ys -> zs        { 1 2 3 } { 3 4 5 } Intersect
                    -> { 3 }
Iterate        x f n -> xs        1 \<< 2 * \>> 10 Iterate
                    -> { 1 2 4 8 16 32 64 128 256 512 }
Last        xs -> x            { 1 2 3 } Last
                    -> 3
Length        xs -> n            { 1 2 3 } Length
                    -> 3.
Map        xs f -> ys        { 1 2 3 } \<< 3 ^ \>> Map
                    -> { 1 8 27 }
Nub        xs -> ys        { 1 2 2 3 2 3 3 } Nub
                    -> { 1 2 3 }
Null        xs -> 0/1        { 1 2 3 } Null
                    -> 0.
Product        xs -> x            { 1 2 3 } Product
                    -> 6
Repeat        x n -> xs        1 5 Repeat
                    -> { 1 1 1 1 1 }
Reverse        xs -> ys        { 1 2 3 } Reverse
                    -> { 3 2 1 }
Scanl        xs x f -> yss        { 1 2 3 } 0 \<< + \>> Scanl
                    -> { 0 1 3 6 }
Scanl1        xs f -> yss        { 1 2 3 } \<< + \>> Scanl1
                    -> { 1 3 6 }
Scanr        xs x f -> yss        { 1 2 3 } 0 \<< + \>> Scanr
                    -> { 6 5 3 0 }
Scanr1        xs f -> yss        { 1 2 3 } \<< + \>> Scanr1
                    -> { 6 5 3 }
Segs        xs -> yss        { 1 2 3 } Segs
                    -> { { } { 3 } { 2 } { 2 3 } { 1 }
                         { 1 2 } { 1 2 3 } }
Seq        x y z -> xs        1 10 2 Seq
                    -> { 1 3 5 7 9 }
Sort        xs p -> ys        { 1 3 2 } \<< < \>> Sort
                    -> { 1 2 3 }
Split        xs n -> ys zs        { 1 2 3 } 2 Split
                    -> { 1 2 } { 3 }
Strcat        xs -> s            { "a" "b" "c" } Strcat
                    -> "abc"
Subs        xs -> yss        { 1 2 3 } Subs
                    -> { { 1 2 3 } { 1 2 } { 1 3 } { 1 }
                         { 2 3 } { 2 } { 3 } { } }
Sum        xs -> x            { 1 2 3 } Sum
                    -> 6
Tail        xs -> ys        { 1 2 3 } Tail
                    -> { 2 3 }
Tails        xs -> yss        { 1 2 3 } Tails
                    -> { { 1 2 3 } { 2 3 } { 3 } { } }
Take        xs n -> ys        { 1 2 3 } 2 Take
                    -> { 1 2 }
TakeWhile    xs p -> ys        { 1 2 3 } \<< 2 < \>> TakeWhile
                    -> { 1 }
Union        xs ys -> zs        { 1 2 3 } { 3 4 5 } Union
                    -> { 1 2 3 4 5 }
Until        x f p -> y        1 \<< 2 * \>> \<< 1000 > \>> Until
                    -> 1024
Unzip        xss -> xs ys        { {1 A} {2 B} {3 C} } Unzip
                    -> { 1 2 3 } { A B C }
Unzip3        xss -> xs ys zs        { {1 A x} {2 B y} {3 C z} } Unzip3
                    -> { 1 2 3 } { A B C } { x y z }
While        x f p -> xs        1 \<< 2 * \>> \<< 1000 < \>> While
                    -> { 1 2 4 8 16 32 64 128 256 512 }
Zip        xs ys -> xss        { 1 2 3 } { A B C } Zip
                    -> { { 1 A } { 2 B } { 3 C } }
Zip3        xs ys zs -> xss        { 1 2 3 } { A B C } { x y z } Zip3
                    -> { { 1 A x } { 2 B y } { 3 C z } }
ZipWith        xs ys f -> xs'        { 1 2 3 } DUP \<< * \>> ZipWith
                    -> { 1 4 9 }
ZipWith3    xs ys zs f -> xs'    { 1 2 3 } DUP DUP \<< * * \>> ZipWith3
                    -> { 1 8 27 }

Notes:

1.  Chars and Strcat are provided to convert between strings and lists of
    single character strings. These are not available in Haskell (nor are they
    needed, since a string already is a list of characters in Haskell), but
    are provided here for your convenience so that you can manipulate strings
    using list processing. Note that Strcat can also be used to concatenate an
    arbitrary list of strings.

2.  Copy and Split should actually be named Cycle and SplitAt, respectively,
    but we retained those names for backward compatibility with previous
    GoferLists versions. Also note that the Diff function (meaning list
    difference) is implemented by an operator (\\) in Haskell.

3.  Copy (a.k.a. Haskell's cycle), Iterate and Repeat take an additional
    integer argument which specifies the number of repetitions or
    iterations. In Haskell these functions return infinite lists instead. This
    is possible because of Haskell's lazy evaluation, but of course this
    wouldn't work in an eager language like RPL.

4.  Foldl/Foldr now take their arguments in reverse order. This breaks
    backward compatibility with previous GoferLists versions, but is
    consistent with other generic list functions like Filter and Map, and
    makes it possible to "curry" these operations just like you would in
    Haskell. E.g., concatenating a list of lists can be done using {} << + >>
    Foldl, just as you'd define concat = foldl (++) [] in Haskell, where the
    "list of lists" parameter is implicit (the {} a.k.a. [] is the initial
    empty list from which the accumulation starts). Note that in order to make
    this work in RPL, the parameters have to be in reverse order, because of
    RPN. Other higher-order list functions like Filter, Find, Iterate, Map,
    Scanl/Scanr, Sort etc. work in an analogous fashion.

5.  Concat, Product, Sum and Strcat are all just special instances of Foldl.
    They could easily be defined in User RPL, but are already included in the
    library for your convenience.

6.  The Seg and Subs function are not in the Haskell library, but work in the
    same fashion as Inits and Tails. Seg returns the list of all consecutive
    sublists of a list, while Subs yields the list of *all* (2^N) sublists.

7.  The Seq function (which is just a simplified frontend for the builtin SEQ)
    provides a quick means to generate an arithmetic sequence, which can be
    used as a replacement for Haskell's [x,y..z] construct.

8.  The Sort function takes an additional order predicate as parameter, so
    that lists can be sorted according to different criteria. E.g., \<< < \>>
    Sort and \<< > \>> Sort sorts lists in ascending and descending order,
    respectively. (Haskell also provides a sortBy function for this purpose,
    but that function takes a special ordering function instead of a binary
    predicate as argument.)

9.  GoferLists also provides a number of operations which implement the usual
    set operations on lists. The Nub function removes duplicates from a list,
    so that the resulting list contains each of its members exactly once. The
    Elem, Insert/Delete, Union/Diff/Intersect functions provide the common set
    operations: membership test, insert/delete a member, set union, difference
    and intersection. The Find function works similar to Elem, but looks for
    an element satisfying the given predicate and returns that element if
    found, NOVAL otherwise. Both functions also have a variation, ElemIndex/
    FindIndex, which returns the index of the element in the list (0. if not
    found) instead.

10. Two additional functions are provided to iterate a function starting from
    an initial value. Until is not actually a list function but is provided
    for your convenience anyway. It iterates a function starting from the
    given value and returns the first of the computed values which satisfies
    the given predicate. E.g., 1 \<< 2 * \>> \<< 1000 > \>> Until returns the
    first power of 2 which is greater than 1000, i.e., 1024. The "dual" of the
    Until function is While which returns the list of all iterated values up
    to the point where the given predicate becomes false. Thus, e.g., 1 \<< 2
    * \>> \<< 1000 < \>> While returns the list of all powers of two below
    1000, { 1 2 4 8 16 32 64 128 256 512 }. This function is not actually part
    of the Haskell library, but is equivalent to a combination of Haskell's
    iterate and takeWhile functions.

11. Zip and Zip3 produce a list of lists instead of a list of tuples as in
    Haskell. The Unzip and Unzip3 functions return two or three result lists
    on the stack, respectively; in Haskell, these functions return a tuple of
    lists instead.


EXAMPLE
=======

Here is a quick and dirty implementation of Erathosthenes' sieve in RPL. This
makes use of GoferLists's Filter, Head, Tail and Seq functions. The central
routine here is SIEVE which just takes away the first list element P (which
already is a prime by virtue of the construction) and invokes itself
recursively on the rest of the list after multiples of P have been removed.

SIEVE:        \<< IF DUP Null NOT THEN DUP Head \-> P
              \<< Tail \<< P MOD 0 \=/ \>> Filter SIEVE    P SWAP + \>>
            END \>>

PRIMES:        \<< 2 SWAP 1 Seq SIEVE \>>

N PRIMES returns the list of prime numbers up to the given number N. For
instance: 50 PRIMES -> { 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 }


Enjoy. :)

Jan 26 2007
Albert Graef <Dr.Graef@t-online.de>

Wikis are great, Contribute :)
Find all posts by this user
Quote this message in a reply
09-15-2018, 10:49 AM
Post: #15
RE: List API (G1CMZ): List Processing API
Thanks. The Listext documentation seems much more comprehensible.
Were Listext to be ported to the Prime, do you see it as being used in RPN mode? Or PPL?

Stephen Lewkowicz (G1CMZ)
Visit this user's website Find all posts by this user
Quote this message in a reply
09-15-2018, 10:59 AM (This post was last modified: 09-15-2018 11:01 AM by pier4r.)
Post: #16
RE: List API (G1CMZ): List Processing API
I believe what is useful is to have the functions and I like HP PPL. I can do HP PPL and RPL, I normally use RPL as I have 4 hp 50g, but otherwise I would use the HP PPL.

And yes ListExt is peak quality for my standards.

Wikis are great, Contribute :)
Find all posts by this user
Quote this message in a reply
09-26-2018, 04:52 PM (This post was last modified: 09-26-2018 05:00 PM by StephenG1CMZ.)
Post: #17
RE: List API (G1CMZ): List Processing API
Version 1.5
Exports ListANS and changes object type definitions.
Adds FLATTEN functions.

Code:


 LOCAL CRID:="List API V1.5 © 2018 StephenG1CMZ";
 LOCAL MORETEXT:="A collection of list routines brought to you by StephenG1CMZ,\n with some from the forum.";
 LOCAL MN:="List.";//Name

 //COMMON
 //LOCAL SL:=1;
 LOCAL NL:="\n";
 EXPORT TYPEFLOAT:=TYPE(3.1);//0
 EXPORT TYPEINT:=TYPE(#3); 
 EXPORT TYPESTR:=TYPE(" ");
 EXPORT TYPECOMPLEX:=TYPE();
 EXPORT TYPEMATRIX:=TYPE([[1]]);
 EXPORT TYPEERROR:=5;//a
 EXPORT TYPELST:=TYPE({});//6
 EXPORT TYPECAS:=TYPE(CAS("nop"));
 EXPORT TYPEFUN:=TYPE('X+Y');//8
 EXPORT TYPEUNIT:=TYPE(1_ m);//9
 //14.?-CAS

 //END COMMON

 //Customise
 EXPORT ListShowErrors:=1;//SHOW ERRORS
 EXPORT ListNumericTypes:={TYPEFLOAT,TYPEINT,TYPECOMPLEX,TYPEMATRIX};
 //Query: Include COMPLEX,LONGFLOAT,MATRIX?
 //End

 //Forward
 ListCOUNTANYDUPLICATES_SORTED(SORTEDLST);
 ListCOUNTITEM(LST,ITEM);
 ListCOUNTITEMS(LST,ITEMS);
 ListIsTYPE(LST,TYPES);
 ListREMOVEDUPLICATES(LST);
 ListREMOVEX(LST,POSN);
 ListSORT(LST);

 //NB In main routines (ie not Python)
 //POSN parameter is >=0 (0=LAST)
 //POSN returned is ≥0 (PPL,0=NOTFOUND)

 EXPORT ListANS;//OUTPUT LIST(WHEN NOT RETURNED)
  //Also, useful temporary results 

 //ERR 
 LOCAL ListErrK:=1;
 LOCAL PyErrK:=3;
 EXPORT ListLastError:=0;
 LOCAL ERRKIND:={"","Error","","Py Error","","","","List Error","ListX Error"};
 //FIX
 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 ListSortError:=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)
 //Error Handling
 BEGIN
  LOCAL PROGML:=Programs();
  LOCAL PROGM:=PROGML(1);//NB:THE USER PROGM RUNNING, NOT THAT RAISING THE ERROR :(
  IF ListShowErrors AND SEVERITY>0 THEN
   MSGBOX(PROGM+":"+MN+" "+ERRKIND(SEVERITY+1)+NL+ERRLST(ERR)+NL+CULPRIT);
  END;
  ListLastError:=ERR;
 END;

 //Lowercase names are well defined (described in Wikipedia or Python Docs)
 //UPPERCASE and CamelCase names are more likely to change

 EXPORT ListAFTER(LST,POSN)
 //Slice After POSN:
 //POSN=0 OR LAST:{}
 BEGIN
  LOCAL FRM:=POSN+1;
  RETURN IFTE((POSN==0 OR FRM>SIZE(LST)),{},LST({FRM,SIZE(LST)}));
 END;

 EXPORT ListANDBOOL(LST,LSTBOOL,NewValue)
 //Replace items ANDed out with NULL(NewValue)
 //EG ({"AA","BB"},{0,1},"CHAR(0)") = {"","BB"}//Note the quotes
 //EG ({11,13},{0,1},"12")//NOMORETHAN12
 //RequirementSpec:
 //http://www.hpmuseum.org/forum/thread-5092.html
 //Usage:
 //http://www.hpmuseum.org/forum/thread-5031.html
 //See also:MaskBOOL
 //NULL=NULL
 BEGIN
  //Guard against empty "" giving syn err
  LOCAL MYNULL:=IFTE(NewValue=="","CHAR(0)",NewValue);
  IF SIZE(LST) AND SIZE(LSTBOOL) THEN
   RETURN EXECON("IFTE(&2,&1,"+MYNULL+")",LST,LSTBOOL);
  END;
  RETURN {};
 END;

 EXPORT ListBEFORE(LST,POSN)
 //Slice Before POSN: 
 //POSN=0: ({1,2},0)={1}
 BEGIN
  LOCAL TOO:=POSN-1;
  IF POSN==0 THEN
    RETURN ListBEFORE(LST,SIZE(LST));
  END;
  RETURN IFTE(TOO>0,LST({1,TOO}),{});
 END;

 EXPORT ListCONCAT(LST1,LST2)
 //CONCATENATE:BUILTIN
 BEGIN
  CONCAT(LST1,LST2);
 END;

 EXPORT ListCOUNTANYDUPLICATES (LST)
 //Preferred-SORTED
 BEGIN
  ListANS:=ListSORT(LST);
  RETURN ListCOUNTANYDUPLICATES_SORTED(ListANS);
 END;

 EXPORT ListCOUNTANYDUPLICATES_SLOW(LST)
 //Caution can be much slower but may be faster
 //REAL LST NO DUPS:5s 
 //INT LST 8000 DUPS:0.2s
 BEGIN
  RETURN SIZE(LST)-SIZE(ListREMOVEDUPLICATES(LST));
 END;

 EXPORT ListCOUNTANYDUPLICATES_SORTED(SortedLST)
 //Count how many duplicates in a sortedlist,Return a REAL INT
 //({1,9,9}=1 dup, {1,2,2,3,3,3}=3 dup)
 //Timings consistent 0.3s
 BEGIN
  LOCAL II;
  LOCAL DUPCOUNT:=0;
  IF SIZE(SortedLST)>1 THEN
   FOR II FROM 1 TO SIZE(SortedLST)-1 DO
    IF SortedLST(II) ==SortedLST(II+1) THEN
     DUPCOUNT:=DUPCOUNT+1;
    END;//IF
   END;//FOR
   //ELSE:SMALL LISTS HAVE NO DUPLICATES
  END;//IF
  RETURN DUPCOUNT;
 END;

 EXPORT ListCOUNTITEMS(LST,ITEMS)
 //ITEMS MAY BE 1 ITEM OR A LIST OF SEPARATE ITEMS
 //SO TO COUNT LISTS, CONTAIN THEM IN A LIST
 //EG {1,{},2},{{}}= 1
 //EG {1,2,3},{2,3} = 2
 //EG {1,{2,3}},{2,3} = 0 (TO SEARCH FOR ITEM {2,3} USE COUNT)
 //ITEMS NULL=0
 //LST NULL=0
 BEGIN
  RETURN SIZE(INTERSECT(LST,ITEMS));
 END;

 EXPORT ListCOUNTS(LST)
 //Given a list
 //Return unique list of occurrences and their occurrence counts as 2 lists
 //to undo: UNCOUNTS(COUNT())
 BEGIN
  LOCAL II;
  LOCAL LSTF:={};
  LOCAL LSTV:=ListREMOVEDUPLICATES(LST);

  FOR II FROM 1 TO SIZE(LSTV) DO
   LSTF(II):=ListCOUNTITEMS(LST,LSTV(II));//FIXED
  END;
  RETURN {LSTV,LSTF};
 END;

 EXPORT ListCOUNTSWITHSORT(LST)
 //As COUNTS but the LSTV output is sorted
 //Puzzle #31
 //This trivial implement is quicker than sorting output lists using SORTN
 //(but using SORTN makes selecting sorting by list2 easier)
 //See also: ListSORTBYOCCURRENCES
 BEGIN
  RETURN ListCOUNTS(ListSORT(LST));
 END;

 EXPORT ListCSV2LIST()
 //Importing the procedure would introduce a dependency(later?)
 BEGIN
  MSGBOX("To parse CSV files/strings to lists use StephenG1CMZ's CSV program.\n")
 END;

 EXPORT ListDIFFER(LST1,LST2)
 //POSITION OF 1st DIFFERENCE
 //FLOAT≠INTEGER
 //SIZE≠SIZE: SZ+1 RETURNED(UNLESS EARLIER DIFFERENCE)
 BEGIN
  LOCAL II:=1;
  LOCAL SZ:=MIN(SIZE(LST1),SIZE(LST2));

  IF EQ(LST1,LST2) THEN
   RETURN 0;
  END;
  //IF SIZE(LST1)≠SIZE(LST2) THEN
  // RETURN −1;
  //END;
  WHILE II≤SZ DO
   IF TYPE(LST1)≠TYPE(LST2) OR LST1(II)≠LST2(II) THEN
    RETURN II;
   END;
   II:=II+1;
  END; 
  RETURN IFTE(SIZE(LST1)>SZ OR SIZE(LST2)>SZ,SZ+1,0);
 END;

 EXPORT ListFIND(LST,ITEM)
 //Find positions of ITEM in LST
 //See http://www.hpmuseum.org/forum/thread-9431.html
 BEGIN 
  LOCAL X,Y;
  LOCAL LSTPOSNS={};

  WHILE X:=POS(LST,ITEM) DO
    LSTPOSNS(0):=(Y:=X+Y);
    LST:=LST({X,SIZE(LST)}+1)
  END;
  RETURN LSTPOSNS;
 END;

 EXPORT ListFLATTENALL(LST)
 BEGIN
  LOCAL II;
  ListANS:={};
  IF TYPE(LST)==TYPELST THEN
   FOR II FROM 1 TO SIZE(LST)  DO 
    IF TYPE(LST(II))==TYPELST THEN
     ListANS:=CONCAT(ListANS,ListFLATTENALL(LST(II)));
    ELSE
     ListANS(0):=LST(II);
    END;
   END;
  ELSE 
   RETURN LST; 
  END;
  RETURN ListANS;
 END;
  
  //TBD FLATTEN
  //If only a few items are lists
  //It is probably worth skipping all this
  //item at a time copying by searching for a LIST
  //and copying a chunk of items
  //TBD FLATTEN

 EXPORT ListFLATTENTOP(LST)
 BEGIN
  LOCAL II,JJ;
  ListANS:={};
  IF TYPE(LST)≠TYPELST THEN 
   RETURN LST;
  END;
  FOR II FROM 1 TO SIZE(LST)  DO 
   IF TYPE(LST(II))==TYPELST THEN
    FOR JJ:= 1 TO SIZE(LST(II)) DO
     ListANS(0):=LST(II,JJ);
    END;
   ELSE
    ListANS(0):=LST(II);
   END;
  END;
  RETURN ListANS;
 END;

 EXPORT ListGETLIST(LST,GETLST)
 //Solves Puzzle #32. POSN≥0.
 //POSN>SIZE(LST):EXCEPTION. RETURN {} FOR THAT ITEM
 BEGIN
 LOCAL II;

  IF SIZE(GETLST) THEN
   IF MAX(GETLST)>SIZE(LST) THEN
    RAISE(MN+"ListGETLIST",EL,IndexOutOfBoundsException,MAX(GETLST)+">"+SIZE(LST),ListErrK);
   END;
   //IFTE GUARDS INDEX>SIZE(LST)
   RETURN MAKELIST(IFTE(GETLST(II)>SIZE(LST),{},LST(GETLST(II))),II,1,SIZE(GETLST));
  END;
  RETURN {};//ASKED TO GET NOTHING
 END;

 EXPORT ListHEAD(LST)
 //List HEAD AKA LISP CAR
 //NULL:ERR
 //PPL FASTER
 //See also:head()
 BEGIN
  IF SIZE(LST) THEN
   RETURN LST(1);
  END;
  RAISE(MN+"ListHEAD",EL,ListIsEmptyError,"",ListErrK);
  RETURN {};
 END;

 EXPORT ListINDEX(LST,ITEM)
 //Despite the confusing name
 //Simple: Return posn of 1st instance of item
 //If you do want to index ITEM, use FIND.
 //NULL: 0
 BEGIN
  RETURN POS(LST,ITEM);
 END;

 EXPORT ListINSERT(LST,POSN,ITEM)
 //INSERT ITEM BEFORE POSN
 //PPL POSN=0 = APPEND
 //Py  POSN=0 = 1ST
 BEGIN
  LOCAL POSNB:=POSN-1;
  LOCAL LSTB:=IFTE(POSN==1,{},LST({1,POSNB}));
  LOCAL LSTA:=LST({POSN,SIZE(LST)});

  IF POSN==0 THEN //IN PPL:
   //IT IS UNCLEAR WHETHER THIS SHOULD APPEND,
   //OR INSERT BEFORE LAST 
   //OPINIONS?
   //TBD();
   RETURN CONCAT(LST,ITEM);
  END;
  RETURN CONCAT(CONCAT(LSTB,ITEM),LSTA);
 END;

 //Query:
 //IsLIST asks-Is parameter this
 //IsNUMERIC,IsSET,IsSORTABLE,IsTYPE ask:Are contents this
 //Change names to clarify?

 EXPORT ListIsLIST(LST)
 //BOOL:Is actual parameter a list_type
 //In PPL lists and sets both 1
 //To check instead that a list contains only lists,
 //use IsTYPE(LST,{DOM_LIST})
 BEGIN
   RETURN (TYPE(LST)==DOM_LIST-1);
 END;

 EXPORT ListIsNUMERIC(LST)
 //Is list currently numeric
 BEGIN 
  RETURN ListIsTYPE(LST,ListNumericTypes);
 END;

 EXPORT ListIsSET(LST)
 //BOOL:Is LST currently a set (no duplicates)
 //A uniquelist (no duplicates) may be a set
 //NULL:1
 BEGIN
  RETURN NOT(ListCOUNTANYDUPLICATES(LST));
 END;

 EXPORT ListIsTYPE(LST,TYPES)
 //TYPES: TYPE OR LIST OF TYPES
 //SEE ALSO:IsNUMERIC
 //MAKELIST IS FASTER THAN [FOR,INCREMENT COUNT] 
 BEGIN
  LOCAL II;

  IF TYPE(TYPES)==DOM_FLOAT-1 THEN RETURN ListIsTYPE(LST,{TYPES});
  END;
 
  IF SIZE(LST) AND SIZE(TYPES) THEN
   ListANS:=MAKELIST(IFTE(POS(TYPES,TYPE(LST(II))),1,0),II,1,SIZE(LST));//List matching types
   RETURN IFTE(ΣLIST(ListANS)==SIZE(LST),1,0); //Count them
  END;
  RAISE(MN+"ListIsTYPE",EL,ListIsEmptyError,"",1);
  //EMPTY LST: LST ALWAYS INDETERMINATE (GUARD) 
  //EMPTY TYPES: 0>NO MATCHES OR 1>NO REJECTS 
  RETURN 0;//INDETERMINATE
 END;

 EXPORT ListMASKBOOL(LST,LSTBOOL,NewValue)
 //Mask selected values
 //Cf ANDBOOL
 //Here 1 selects replace, not 0
 //NULL=NULL
 BEGIN 
  //Guard against empty "" giving syn err
  LOCAL MYNULL:=IFTE(NewValue=="","CHAR(0)",NewValue);
  IF SIZE(LST) AND SIZE(LSTBOOL) THEN
   RETURN EXECON("IFTE(&2,"+MYNULL+",&1)",LST,LSTBOOL);
  END;
  RETURN {};
  //Equivalent to
  //RETURN ListANDBOOL(LST,NOT(LSTBOOL),NewValue);
 END;

 EXPORT ListMEANS()
 BEGIN
  MSGBOX("StephenG1CMZ's MEANS program implements several means.");
 END;

 EXPORT ListMEDIAN(LST)
 BEGIN
  IF SIZE(LST) THEN
   RETURN(median(LST));
  END;
  RAISE(MN+"ListMEDIAN",EL,ListIsEmptyError,"",ListErrK);//(NO MEDIAN)
  RETURN {};///
 END;
 //Query:What_error to return?
 //NAN OR {} MIGHT BE THE MEDIAN VALUE
 EXPORT ListMEDIAN2(LSTV,LSTF)
 BEGIN
  IF SIZE(LSTV) AND SIZE(LSTF) THEN
   RETURN(median(LSTV,LSTF));
  END;
  RAISE(MN+"ListMEDIAN2",EL,ListIsEmptyError,"",ListErrK);
  RETURN {};///
 END;

 EXPORT ListMODE(L)
 //From http://www.hpmuseum.org/forum/thread-9393.html
 BEGIN
 LOCAL l1,l2;
 l1:=UNION(L);
 l2:=MAKELIST(SIZE(INTERSECT(L,l1(I))),I,1,SIZE(l1));
 l2:=(l2==MAX(l2))*MAKELIST(I,I,1,SIZE(l1));
 l2:=remove(0,l2);
 MAKELIST(l1(l2(I)),I,1,SIZE(l2));
END;
   
 //MODE1_DEPRECATED is deprecated as it is slower
 //MODE2 is likely slower too,
 //but may be useful as parameters differ
 //(retain for comparisons speed and testing)    

 EXPORT ListMODE2(LSTV,LSTF)
 //Get MODES of ItemXFrequency Lists
 //Empty=Empty
 BEGIN
  LOCAL II;
  LOCAL MODESLST:={};
  LOCAL MODEPOSNS:={};

  IF SIZE(LSTF) AND SIZE(LSTV) THEN
   //Find MODES
   MODEPOSNS:=ListFIND(LSTF,MAX(LSTF));
  
   FOR II FROM 1 TO SIZE(MODEPOSNS) DO
    MODESLST(II):=LSTV(MODEPOSNS(II));
   END;//FOR
  END;//IF
  RETURN MODESLST;
 END;

 EXPORT ListMODE1_DEPRECATED(LST)
 //Get MODES of LST : Empty = Empty
 BEGIN
  //Make uniquelst and count
  ListANS:=ListCOUNTS(LST);//FIXED
  
  RETURN ListMODE2(ListANS(1),ListANS(2));
 END;

 EXPORT ListPOP(LST,POSN)
 //POP POSN OFF LIST
 BEGIN
  LOCAL ITEM;
  IF SIZE(LST) THEN
   ITEM:=LST(IFTE(POSN,POSN,SIZE(LST)));//0=>LAST
   ListANS:=ListREMOVEX(LST,POSN);
  ELSE
   RAISE(MN+"ListPOP",EL,ListIsEmptyError,"",ListErrK);
   ITEM:={};
   ListANS:={};
  END;   
  //RETURN POPPED ITEM
  //BUT ALSO SAVE SHORTENED LST
  RETURN ITEM;
 END;

 EXPORT ListPOPLAST(LST)
 //POP POSN OFF LIST
 //Py: POP()
 BEGIN
  RETURN ListPOP(LST,SIZE(LST)); 
 END;

 EXPORT ListremoveX(LST,POSN)
 // CAS ALTERNATIVE TO REMOVEX:MAY BE SLOW
 //See 
 //http://www.hpmuseum.org/forum/thread-9406.html and
 //http://www.hpmuseum.org/forum/thread-7987.html?highlight=suppress 
 //NULL=NULL,POSN>SZE=LST
 BEGIN
  IF POSN THEN
   RETURN suppress(LST,POSN);
  END;
  RETURN suppress(LST,SIZE(LST));//0=LAST
 END;

 EXPORT ListREMOVEX(LST,POSN)
 //REMOVE 1 ITEM AT POSN
 //NULL=NULL,POSN>SIZE=LST (NOWT REMOVED)
 BEGIN
  LOCAL LSTB,LSTA;

  IF POSN THEN
   LSTB:=ListBEFORE(LST,POSN);
   LSTA:=ListAFTER (LST,POSN);
   RETURN CONCAT(LSTB,LSTA);
  ELSE
   //PPL: 0=Remove Last Item
   RETURN ListREMOVEX(LST,SIZE(LST));
   //Py: 0=RemoveFirst ie return TAIL
  END;
 END;

 EXPORT ListremoveCAS(LST,ITEM) 
 //CAS version slower
 //NULL=NULL
 BEGIN
  RETURN remove(ITEM,LST);
 END;

 EXPORT ListREMOVE(LST,ITEM)
 //Remove 1 instance of ITEM
 //NULL=NULL 
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  IF POSN THEN
   RETURN ListREMOVEX(LST,POSN);
  END;
  RAISE(MN+"ListREMOVE",EL,ItemNotFoundError,ITEM,0);
  RETURN LST;//NOTHING TO REMOVE
 END;

 EXPORT ListREMOVEDUPLICATES(LST)
 //RESULT WITH DUPLICATES JUST ONCE 
 //Native: Sequence NOT determined but seems same
 //From #21
 BEGIN
  RETURN UNION(LST);
 END;

 EXPORT ListREMOVEITEM(LST,ITEM)
 //ALL INSTANCES.PUZZLE #40.
 BEGIN
  LOCAL II;
  LOCAL FOUND:=ListFIND(LST,ITEM);
  IF SIZE(FOUND) THEN
   ListANS:=LST;
   //Remove from right:earlier posns unchanged
   FOR II FROM SIZE(FOUND) DOWNTO 1 DO
    ListANS:=ListREMOVEX(ListANS,FOUND(II));
   END;
   RETURN ListANS;
  END;//IF
  RETURN LST;//NOTHING REMOVED 
 END;

 //NB replace in CAS is different
 EXPORT ListREPLACE(LST,ITEM,ITEM2)
 //Replace instances of ITEM with ITEM2
 BEGIN
  LOCAL II;
  LOCAL FOUND:=ListFIND(LST,ITEM);
  IF SIZE(FOUND) THEN
   ListANS:=LST;
   FOR II FROM 1  TO SIZE(FOUND)  DO
    ListANS(FOUND(II)):=ITEM2;
   END;
  ELSE
   RETURN LST;
  END;
  RETURN ListANS; 
 END;

 EXPORT ListSHUFFLE(LST_NUM)
 //SHUFFLE NUM: SHUFFLE 1..N INDEXES 
 //SHUFFLE LST: SHUFFLE LST
 //N<0:GUARD:UNSHUFFLED INDEX
 //NULL OR 0 OR >10000: NULL 
 BEGIN
  LOCAL II,NUM;
  IF TYPE(LST_NUM)=DOM_FLOAT-1 THEN
   NUM:=IFTE(LST_NUM>10000,0,LST_NUM);
   IF LST_NUM<0 THEN //GUARD NEGATIVES (AVOID CRASH)
    RETURN MAKELIST(II,II,1,ABS(NUM));//UNSHUFFLED
   END;
  END;
  RETURN mat2list(randperm(LST_NUM));
 END;

 EXPORT ListSLICE(LST,FRM,TOO)
 //RETURN PART OF LIST (AKA SUB)
 //SYNTAX HINT
 //SUGGEST ALSO IMPL (LST,{2,[3]})
 //FRM≤TOO:Bad Inputs={}
 BEGIN
  LOCAL TTOO:=IFTE(TOO==0,SIZE(LST),TOO); //TO 0==LAST
  LOCAL TFRM:=IFTE(FRM==0,SIZE(LST),FRM); //FRM 0==LAST
  //MSGBOX("SLICE "+{FRM,TOO});
  IF TFRM>TTOO THEN
    //RAISE(IndexOutOfBoundsException,FRM,ListErrK);//Maybe a new error
    RETURN {};
  END; 
  RETURN LST({TFRM,TTOO});
 END;

 EXPORT ListSORT(LST)
 //This implementation uses native SORT
 //On old compilers See known bugs 
 //This will not affect MODE other than changing ordering 
 //Native SORT falls over:Use IsSORTABLE to check 1st
 //NOTE TO DEVELOPERS:
 //NB1:Sorting a list of size 1 is trivial, so test using 2to see if a t 
 BEGIN
  IF TYPE(LST)≠DOM_LIST-1 THEN 
   RAISE(MN+"ListSORT",EL,ListSortError,"",ListErrK);
  END;
  RETURN SORT(LST);
 END;

 EXPORT ListTAIL(LST)
 //List TAIL AKA LISP CDR
 //NULL:ERR
 //(SOME USE TAIL=LAST NOT TAIL=CDR)
 //PPL FASTER
 //See also:tail
 BEGIN
  IF SIZE(LST) THEN
   RETURN LST({2,SIZE(LST)});
  END;
  RAISE(MN+"ListTAIL",EL,ListIsEmptyError,"",ListErrK);
  RETURN {};
 END;

 EXPORT ListToSET(LST)
 //In addition to making the list like a set
 //wibni we could track those tnat ARE sets.
 //In PPL sets are indistinguishable
 BEGIN
  RETURN ListREMOVEDUPLICATES(LST);
 END;

 EXPORT ListUNCOUNTS(LSTV,LSTF)
 //INVERSE OF COUNTS. Syntaxes:
 // IsList(LSTF) -> (LSTV,LSTF)
 // ELSE         -> ({LSTV,LSTF},−1) :MATCHES ListCOUNTS
 // NULL         -> NULL
 //Given V and F yield V,F times
 
 //In a COUNTS list V is unique and F>0
 //But We handle V with F=0 and V nonunique too
 BEGIN
  LOCAL II,JJ;
  LOCAL LST:={};
 
  IF TYPE(LSTF)==TYPE({}) THEN
   IF SIZE(LSTV) AND SIZE(LSTF) THEN
    FOR II FROM 1 TO SIZE(LSTV) DO
     //F:0-NOP >0 MAKE (<0 IGNORED , OR COULD RAISE) 
     IF LSTF(II)>0 THEN //V WITH F>0
      LST:=CONCAT(LST,MAKELIST(LSTV(II),JJ,1,LSTF(II)));
     END;
    END;//FOR
   END;
  ELSE //LSTF NOT A LST
   IF SIZE(LSTV)≥2 THEN
    RETURN ListUNCOUNTS(LSTV(1),LSTV(2)); 
   END;
  END;
  RETURN LST;
 END;

 EXPORT ListVERSION()
 BEGIN
  RETURN CRID;
 END;

 // Python names(LC) prefixed Py ()
 // Py  syntax: Lst.append(ITEM) etc 
 // PPL syntax: Lst:=Pyappend(Lst,ITEM)
 // Py indexes from 0 but not yet implemented
 // These names are inspired by Py, 
 // but may never provide exact equivalents.
 
 //Currently,0 and allindexes are PPL-like
 //Thus it achieves compatability with 
 //PPL(0), and CAS-Python:S-Beta (like PPL, supposedly).
 //but not Python

 EXPORT Pyappend(LST,ITEM)
 //Python analogue
 //append a single item
 //NB IF List prefix is dropped conflict with CAS.append (CAS.append is slower)
 //NULL LST: {ITEM}
 // (LST,{ITEMLST}) ADDS 1 ITEM (A LST)EG({1},{2,3}={1,{2,3}})
 BEGIN
  RETURN LST(0):=ITEM; 
 END;

 EXPORT Pyclear(LST)
 //Python analogue
 //Py :ALSO DELETES LIST (cf CAS purge)
 BEGIN 
  RETURN {};
 END;

 EXPORT Pycopy(LST)
 //Python analogue
 //Py: A shallow copy PPL: simple copy
 BEGIN
  RETURN LST;
 END;

 EXPORT Pycount (LST,ITEM)
 //Python analogue
 //Count instances of an ITEM:(WHICH MAY BE A LIST=1ITEM)
 //NB do not confuse with CAS.count(Test,Lst)
 BEGIN  
  RETURN ListCOUNTITEMS(LST,{ITEM});
 END;

 EXPORT Pyextend(LST,LST2)
 //Python analogue
 //Py :Concat items in LST2 to LST
 //Query: If listfull, should we add some or none
 //PPL:LST2 may be an item 
 BEGIN
  RETURN CONCAT(LST,LST2);
 END;

 EXPORT Pyindex(LST,ITEM)
 //Python analogue
 //Py :Return index (or ValueErr)

 //TBD START:END LIMIT RANGE SEARCHED WITHOUT CHANGING INDEX
 BEGIN
  LOCAL LX:=ListINDEX(LST,ITEM); 
  IF LX==0 THEN
   RAISE(MN+"Pyindex",EL,ValueError,ITEM,PyErrK);//Py:NotFound => an error
  END;
  RETURN LX; 
 END;

 EXPORT Pyinsert(LST,POSN,ITEM)
 //Python analogue
 //Py :Insert ITEM before POS
 BEGIN
  RETURN ListINSERT(LST,POSN,ITEM); 
 END;

 EXPORT Pypop(LST,POSN)
 //Python analogue
 //Py :Pop item (Posn Omit:Last)
 //PPL:Posn reqd
 BEGIN
  IF POSN==0 THEN
   TBD();
  END;
  RETURN ListPOP(LST,POSN);
 END;

 EXPORT PypopLast(LST)
 //Python analogue
 //Py :Pop item (Posn Omit:Last)
 //PPL:Twofunctions
 BEGIN
  RETURN ListPOPLAST(LST);
 END;

 EXPORT Pyremove(LST,ITEM)
 //Python analogue
 //ALSO NOTE remove in CAS
 //Py :Remove 1st ITEM,ERR IF NONE
 BEGIN
  LOCAL POSN:=POS(LST,ITEM);
  IF POSN THEN
   RETURN ListREMOVEX(LST,POSN);
  END;
  //ELSE NOTHING TO REMOVE
  RAISE(MN+"Pyremove",EL,ItemNotFoundError,ITEM,PyErrK);
  RETURN 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(1):="21. ListREMOVEDUPLICATES";
  LST(2):="31. ListCOUNTSWITHSORT";
  LST(3):="32. ListGETLIST";
  LST(4):="40. ListREMOVEITEM";
  LST(5):="41. ListCumSum";
  CHOOSE(VR,MN+"Puzzles (See thread)",LST);
 END;

 EXPORT ListPythonAnalogues ()
 BEGIN
  LOCAL KK;
  LOCAL PyFuns:={
   "append item",
   "clear list",
   "copy list",
   "count item instances",
   "extend list by list2",
   "index item in list",
   "insert item before posn",
   "pop item at posn from list",
   "poplast",
   "remove instance of item"};
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,MN+"Py...",PyFuns)

 END;

EXPORT ListSeeAlso ()
 BEGIN
  LOCAL KK;
  LOCAL CatFuns:={
   "append:slower",
   "count",
   "DIFFERENCE",
   "head-slower",
   "intersect-fast(AND)",
   "list2mat",
   "mat2list",
   "prepend",
   "quantile",
   "quartile1",
   "quartile3",
   "quartiles",
   "remove",
   "replace",
   "suppress",
   "tail:slower",
   "union",
   "&StephenG1CMZ's SORT... program"};
  //Cannot call SORTAPI as List compiles 1st
  //Just Listed as a reminder:not Selectable
  CHOOSE(KK,MN+" Relevant Cat Functions",CatFuns)
 END;

 EXPORT ListExamples()
 //In real use, use XXX:=List...()
 BEGIN
  LOCAL LL:={1,2,3,4,5,6,7,8,9};
  LOCAL LLL:=CONCAT(LL,LL);
  PRINT();
  PRINT(ListVERSION);
  PRINT("A");
  PRINT(ListAFTER(LL,2));
  PRINT(ListANDBOOL({1,12},{0,1},"122"));
  PRINT(ListANDBOOL({"AA","BB"},{0,1},"CHAR(0)"));
  PRINT("B");
  PRINT(ListBEFORE(LL,2));
  PRINT("C");
  PRINT(ListCONCAT(LL,LL));
  PRINT(ListCOUNTANYDUPLICATES_SLOW({}));
  PRINT(ListCOUNTANYDUPLICATES_SORTED({}));
  PRINT(ListCOUNTANYDUPLICATES({0,2,2,2}));
  PRINT(ListCOUNTITEMS({},2));
  PRINT(ListCOUNTITEMS(LL,{2,3}));
  PRINT(ListCOUNTS(LLL));
  //PRINT(ListUNCOUNTS(ListCOUNTS(LLL)));
  PRINT(ListCOUNTSWITHSORT(LLL));
  PRINT("D"); 
  PRINT(ListDIFFER(LL,LL));
  PRINT(ListDIFFER(LL,CONCAT(LL,2)));
  PRINT("F");
  PRINT(ListFIND(CONCAT(LL,LL),2));
  PRINT(ListFLATTENALL({1,{2,{3,4}}}));
  PRINT(ListFLATTENTOP({1,{2,{3,4}}}));
  PRINT("G");
  PRINT(ListGETLIST(LL,{5,3}));
  PRINT("HI");
  PRINT(ListHEAD(LL));
  PRINT(ListINDEX(LL,2));
  PRINT(ListINSERT(LL,2,4));
  PRINT("Is");
  PRINT(ListIsLIST(5));
  PRINT(ListIsNUMERIC({1,2,#3}));
  PRINT(ListIsSET(LL));
  PRINT(ListIsTYPE({3.4},1-1));
  PRINT("MNO");
  PRINT(ListMASKBOOL({1,12},{0,1},"122"));
  PRINT(ListMASKBOOL({"AA","BB"},{0,1},"CHAR(0)"));
  PRINT("P");
  PRINT(ListPOP(LL,2));LL:=ListANS;
  PRINT(ListPOPLAST(LL));LL:=ListANS;
  PRINT("R");
  PRINT(ListREMOVEX(LL,2));
  PRINT(ListREMOVE(LL,9));
  PRINT("S");
  PRINT(ListSHUFFLE(−52));
  PRINT(ListSHUFFLE(52));
  PRINT(ListSHUFFLE({"R","G","B"}));
  PRINT(ListSLICE({1,2,3,4},2,3));
  PRINT(ListSORT(LL));
  PRINT("T");
  PRINT(ListTAIL(LL));
  PRINT(ListToSET({1,2,2}));
  PRINT("STATS");
  PRINT(ListMEDIAN(LL));
  PRINT(ListMODE({"AC","DC"})); 
 
  PRINT("Exampled");
  //RETURN 0; 
 END;

 //These alternative implements are slower:
 //They can be removed but may be useful for testing
 EXPORT Listcountanyduplicates_(LST)
 //SLOWER
 BEGIN
  LOCAL LL:=UNION(LST);
  RETURN (SIZE(LST)-SIZE(LL));
 END;

 EXPORT LIST()
 BEGIN
  ABOUT();
  //ListExamples();
 END;

Stephen Lewkowicz (G1CMZ)
Visit this user's website Find all posts by this user
Quote this message in a reply
09-26-2018, 08:15 PM
Post: #18
RE: List API (G1CMZ): List Processing API
I will second the recommendation to add commands from ListExt and GoferLists, as warranted, to the List API. However, I would prefer that commands that duplicate existing PPL functionality not be included. The reason being that every app adds more command names to the Prime's catalog, making the catalog more difficult to search.

Thanks for your continuing efforts on this app.

John
Find all posts by this user
Quote this message in a reply
10-03-2018, 07:04 AM (This post was last modified: 10-03-2018 07:14 AM by StephenG1CMZ.)
Post: #19
RE: List API (G1CMZ): List Processing API
Thanks for pointing out that difficulty John. I hadn't considered that.
There are certainly several functions I could remove - but there will inevitably be a large number that are needed.

Would it help if instead of prefixing the names with "List", some other prefix were used?
Like Z perhaps, thus placing it near the end of the catalogue (only 4 other names, plus some symbols), or Y (no other names in the catalogue)?
Or would it still be inconvenient there?

Stephen Lewkowicz (G1CMZ)
Visit this user's website Find all posts by this user
Quote this message in a reply
10-03-2018, 01:43 PM
Post: #20
RE: List API (G1CMZ): List Processing API
(10-03-2018 07:04 AM)StephenG1CMZ Wrote:  Would it help if instead of prefixing the names with "List", some other prefix were used?
Like Z perhaps, thus placing it near the end of the catalogue (only 4 other names, plus some symbols), or Y (no other names in the catalogue)?
Or would it still be inconvenient there?

I'm not sure what the best solution is. The problem as I see it is that the Prime's catalog has a huge number of commands, most of which are not in the toolbox menus. This forces one to either type command names in or search through the catalog for them.

This issue is compounded be each app adding its own commands to the catalog as well. I think that the best approach is to minimize the number of new commands and hope that the fine folks at HP can come up with a way to better organize the catalog and toolbox.

John
Find all posts by this user
Quote this message in a reply
Post Reply 




User(s) browsing this thread: 1 Guest(s)