procedure file2lst: create list from lines in file procedure imag2lst: convert limage() output to list procedure l_Bscan: begin list scanning procedure l_Escan: end list scanning procedure l_any: any() for list scanning procedure l_bal: bal() for list scanning procedure l_find: find() for list scanning procedure l_many: many() for list scanning procedure l_match: match() for list scanning procedure l_move: move() for list scanning procedure l_pos: pos() for list scanning procedure l_tab: tab() for list scanning procedure l_upto: upto() for list scanning procedure llayer: interleave lists with layering procedure lcompact: compact sequence procedure lclose: close open palindrome procedure lcomb: list combinations procedure ldecollate: list decollation procedure ldelete: delete specified list elements procedure ldupl: list term duplication procedure lequiv: compare lists for equivalence procedure levate: elevate values procedure lextend: list extension procedure lfliph: list horizontal flip (reversal) procedure lflipv: list vertical flip procedure limage: list image procedure lcollate: generalized list collation procedure lconstant: test list for all terms equal procedure lindex: generate indices for items matching x procedure linterl: list interleaving procedure llpad: list padding at left procedure lrunup: list run up procedure lrundown: list run up procedure lltrim: list left trimming procedure lmap: list mapping procedure lresidue: list residue procedure lpalin: list palindrome procedure lpermute: list permutations procedure lreflect: list reflection procedure lremvals: remove values from list procedure lrepl: list replication procedure lreverse: list reverse procedure lrotate: list rotation procedure lrpad: list right padding procedure lrtrim: list right trimming procedure lshift: shift list terms procedure lst2str: convert list to string procedure lswap: list element swap procedure lunique: keep only unique list elements procedure lmaxlen: size of largest list entry procedure lminlen: size of smallest list entry procedure sortkeys: extract keys from sorted list procedure sortvalues: extract values from sorted list procedure str2lst: list from string
link lists
March 5, 2003; Ralph E. Griswold
Contributor: Richard L. Goerwitz
This file is in the public domain.
file2lst(s) create list from lines in file imag2lst(s) convert limage() output to list l_Bscan(e1) begin list scanning l_Escan(l_OuterEnvir, e2) end list scanning l_any(l1,l2,i,j) any() for list scanning l_bal(l1,l2,l3,l,i,j bal() for list scanning l_find(l1,l2,i,j) find() for list scanning l_many(l1,l2,i,j) many() for list scanning l_match(l1,l2,i,j) match() for list scanning l_move(i) move() for list scanning l_pos(i) pos() for list scanning l_tab(i) tab() for list scanning l_upto(l1,l2,i,j) upto() for list scanning lclose(L) close open palindrome lcomb(L,i) list combinations lcompact(L) compact list, mapping out missing values ldecollate(I, L) list decollation ldelete(L, spec) list deletion ldupl(L, i) list term duplication lequiv(L1, L2) list equivalence levate(L, m, n) list elevation lextend(L, i) list extension lfliph(L) list horizontal flip (reversal) lflipv(L) list vertical flip limage(L) unadorned list image lindex(L, x) generate indices of L whose values are x lcollate(L1, L2, ...) list collation; like linterl() except stops on short list lconstant(L) succeeds and returns element if all are the same linterl(L1, L2) list interleaving llayer(L1, L2, ...) layer and interleave L1, L2, ... llpad(L, i, x) list padding at left lltrim(L, S) list left trimming lmap(L1,L2,L3) list mapping lpalin(L, x) list palindrome lpermute(L) list permutations lreflect(L, i) returns L concatenated with its reversal to produce palindrome; the values of i determine "end conditions" for the reversal: 0 omit first and last elements; default 1 omit first element 2 omit last element 3 don't omit element lremvals(L, x1, x2, ...) remove values from list lrepl(L, i) list replication lresidue(L, m, i) list residue lreverse(L) list reverse lrotate(L, i) list rotation lrpad(L, i, x) list right padding lrundown(L1, L2, L3) list run down lrunup(L1, L2, L3) list run up lrtrim(L, S) list right trimming lshift(L, i) shift list terms lst2str(L) string from concatenated values in L lswap(L) list element swap lunique(L) keep only unique list elements lmaxlen(L, p) returns the size of the largest value in L. If p is given, it is applied to each string as as a "length" procedure. The default for p is proc("*", 1). lminlen(L, p) returns the size of the smallest value in L. If p is given, it is applied to each string as as a "length" procedure. The default for p is proc("*", 1). sortkeys(L) returns list of keys from L, where L is the result of sorting a table with option 3 or 4. sortvalues(L) return list of values from L, where L is the result of sorting a table with option 3 or 4. str2lst(s, i) creates list with i-character lines from s. The default for i is 1. ____________________________________________________________ About List Mapping The procedure lmap(L1,L2,L3) maps elements of L1 according to L2 and L3. This procedure is the analog for lists of the built-in string-mapping function map(s1,s2,s3). Elements in L1 that are the same as elements in L2 are mapped into the corresponding ele- ments of L3. For example, given the lists L1 := [1,2,3,4] L2 := [4,3,2,1] L3 := ["a","b","c","d"] then lmap(L1,L2,L3) produces a new list ["d","c","b","a"] Lists that are mapped can have any kinds of elements. The operation x === y is used to determine if elements x and y are equivalent. All cases in lmap are handled as they are in map, except that no defaults are provided for omitted arguments. As with map, lmap can be used for transposition as well as substitution. Warning: If lmap is called with the same lists L2 and L3 as in the immediately preceding call, the same mapping is performed, even if the values in L2 and L3 have been changed. This improves performance, but it may cause unexpected effects. This ``caching'' of the mapping table based on L2 and L3 can be easily removed to avoid this potential problem. ____________________________________________________________ About List Scanning by Richard L. Goerwitz PURPOSE: String scanning is terrific, but often I am forced to tokenize and work with lists. So as to make operations on these lists as close to corresponding string operations as possible, I've implemented a series of list analogues to any(), bal(), find(), many(), match(), move(), pos(), tab(), and upto(). Their names are just like corresponding string functions, except with a prepended "l_" (e.g. l_any()). Functionally, the list routines parallel the string ones closely, except that in place of strings, l_find and l_match accept lists as their first argument. L_any(), l_many(), and l_upto() all take either sets of lists or lists of lists (e.g. l_tab(l_upto([["a"],["b"],["j","u","n","k"]])). Note that l_bal(), unlike the builtin bal(), has no defaults for the first four arguments. This just seemed appropriate, given that no precise list analogue to &cset, etc. occurs. The default subject for list scans (analogous to &subject) is l_SUBJ. The equivalent of &pos is l_POS. Naturally, these variables are both global. They are used pretty much like &subject and &pos, except that they are null until a list scanning expression has been encountered containing a call to l_Bscan() (on which, see below). Note that environments cannot be maintained quite as elegantly as they can be for the builtin string-scanning functions. One must use instead a set of nested procedure calls, as explained in the _Icon Analyst_ 1:6 (June, 1991), p. 1-2. In particular, one cannot suspend, return, or otherwise break out of the nested procedure calls. They can only be exited via failure. The names of these procedures, at least in this implementation, are l_Escan and l_Bscan. Here is one example of how they might be invoked: suspend l_Escan(l_Bscan(some_list_or_other), { l_tab(10 to *l_SUBJ) & { if l_any(l1) | l_match(l2) then old_l_POS + (l_POS-1) } }) Note that you cannot do this: l_Escan(l_Bscan(some_list_or_other), { l_tab(10 to *l_SUBJ) & { if l_any(l1) | l_match(l2) then suspend old_l_POS + (l_POS-1) } }) Remember, it's no fair to use suspend within the list scanning expression. l_Escan must do all the suspending. It is perfectly OK, though, to nest well-behaved list scanning expressions. And they can be reliably used to generate a series of results as well. ____________________________________________________________ Here's another simple example of how one might invoke the l_scan routines: procedure main() l := ["h","e","l","l","o"," ","t","t","t","h","e","r","e"] l_Escan(l_Bscan(l), { hello_list := l_tab(l_match(["h","e","l","l","o"])) every writes(!hello_list) write() # Note the nested list-scanning expressions. l_Escan(l_Bscan(l_tab(0)), { l_tab(l_many([[" "],["t"]]) - 1) every writes(!l_tab(0)) write() }) }) end The above program simply writes "hello" and "there" on successive lines to the standard output. ____________________________________________________________ PITFALLS: In general, note that we are comparing lists here instead of strings, so l_find("h", l), for instance, will yield an error message (use l_find(["h"], l) instead). The point at which I expect this nuance will be most confusing will be in cases where one is looking for lists within lists. Suppose we have a list, l1 := ["junk",[["hello"]," ",["there"]],"!","m","o","r","e","junk"] and suppose, moreover, that we wish to find the position in l1 at which the list [["hello"]," ",["there"]] occurs. If, say, we assign [["hello"]," ",["there"]] to the variable l2, then our l_find() expression will need to look like l_find([l2],l1) ____________________________________________________________ Extending scanning to lists is really very difficult. What I think (at least tonight) is that scanning should never have been restricted to strings. It should have been designed to operate on all homogenous one-dimensional arrays (vectors, for you LISPers). You should be able, in other words, to scan vectors of ints, longs, characters - any data type that seems useful. The only question in my mind is how to represent vectors as literals. Extending strings to lists goes beyond the bounds of scanning per-se. This library is therefore something of a stab in the dark.