Post Reply 
List API (G1CMZ): List Processing API
10-28-2018, 11:22 PM (This post was last modified: 10-28-2018 11:28 PM by StephenG1CMZ.)
Post: #21
RE: List API (G1CMZ): List Processing API
Version 1.6
ListTRANSPOSE added.
Some functions unexported or renamed to minimise global impact.
Code:

LOCAL CRID:="List API V1.6 © 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;

 ListCONCAT(LST1,LST2) //UNEXPORTED
 //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;

 ListINDEX(LST,ITEM) //UNEXPORTED
 //Despite the confusing name (matching Py)
 //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,{TYPELST})
 BEGIN
   RETURN (TYPE(LST)==TYPELST);
 END;

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

 ListIsSET(LST) //UNEXPORTED
 //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;

 ListMODE1_DEPRECATED(LST) //UNEXPORTED
 //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;

 ListremoveCAS(LST,ITEM) //UNEXPORTED
 //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) //UNEXPORT?
 //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)≠TYPELST 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;

 ListToSET(LST) //UNEXPORTED
 //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 ListTRANSPOSE(LST)
 //LIST TRANSPOSE
 //WITH A 2D LST TRN(TRN(LST)) RETURNS ORIGINAL LIST
 //A 1D LIST HAS NO PROPER TRANSPOSE AND MIGHT NOT RETURN USEFUL LST
 //NOTE This is similar to the obvious builtin
 //PRINT(mat2list(transpose(list2mat({{1,2,3},{4,5,6}}))));
 //But the builtin unexpectedly flattens too 
 BEGIN
  LOCAL II,JJ;
  LOCAL OUT:={};
  
  FOR II FROM 1 TO SIZE(LST)  DO
    IF TYPE(LST(II))==TYPE({}) THEN //2D
     FOR JJ FROM 1 TO SIZE(LST(II)) DO
      OUT(JJ,II):=LST(II,JJ);
     END;//FOR
    ELSE 
     //GUARD FLAT LIST//WHATS GOOD HERE? AN ERR MAY BE BETTER
     //NEITHER OF THESE ARE IDEAL IN ALL CASES
     OUT(II):=LST(II); 
     //OUT(II):={LST(II)};
    END;//IF
  END;//FOR
  
  RETURN ListANS:=OUT;
 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 MyVERSION()
 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 Examples()
 //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(MyVERSION);
  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(ListTRANSPOSE({{1,2,3},{4,5,6}}));
  //PRINT(mat2list(transpose(list2mat({{1,2,3},{4,5,6}}))));
  PRINT("STATS");
  PRINT(ListMEDIAN(LL));
  PRINT(ListMODE({"AC","DC"})); 
 
  PRINT("Exampled");
  PRINT(MyVERSION);
  //RETURN 0; 
 END;

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

 EXPORT LIST()
 BEGIN
  ABOUT();
  //Examples();
 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-28-2018 11:22 PM



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