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.