Post Reply 
List API (G1CMZ): List Processing API
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)
https://my.numworks.com/python/steveg1cmz
Visit this user's website Find all posts by this user
Quote this message in a reply
Post Reply 


Messages In This Thread
RE: List API (G1CMZ): List Processing API - StephenG1CMZ - 10-31-2017 11:23 PM



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