4. Arrays

Introduction

# PicoLisp doesn't support arrays as contiguous pieces of memory.
# Instead, the standard Lisp linked lists are used.
#-----------------------------
(setq Nested '(this that the other))
(setq Nested '(this that (the other)))
#-----------------------------
(setq Tune '("The" "Star-Spangled" "Banner"))
#-----------------------------

Specifying a List In Your Program

#-----------------------------
(setq A '("quick" "brown" "fox"))
#-----------------------------
(setq A '(Why are you teasing me?))
#-----------------------------
: (setq Lines (make (char) (while (line T) (link @))))
The boy stood on the burning deck,
It was as hot as glass.

-> ("The boy stood on the burning deck," "It was as hot as glass.")
#-----------------------------
(setq Bigarray
   (in "mydatafile"
      (make
         (until (eof)
            (link (line T)) ) ) ) )
#-----------------------------
(setq
   PerlHost "www.perl.com"
   HostInfo (in (list 'nslookup PerlHost) (till NIL T)) )
#-----------------------------
: (split (chop "Costs only $4.95") " ")
-> (("C" "o" "s" "t" "s") ("o" "n" "l" "y") ("$" "4" "." "9" "5"))

: (mapcar pack (split (chop "Costs only $4.95") " "))
-> ("Costs" "only" "$4.95")
#-----------------------------
(setq Ships '("Niña" "Pinta" "Santa María"))
#-----------------------------

Printing a List with Commas

#-----------------------------
: (pack "The " (glue ", " '(big brown dirty hungry)) " fox")
-> "The big, brown, dirty, hungry fox"
#-----------------------------
(setq Array '(red yellow green))

: (prinl "I have " Array " marbles.")
I have redyellowgreen marbles.

: (prinl "I have " (glue " " Array) " marbles.")
I have red yellow green marbles.
#-----------------------------
# download the following standalone program
#!/usr/bin/picolisp /usr/lib/picolisp/lib.l
# commify_series - show proper comma insertion in list output

(de Lists
   ("just one thing")
   ("Mutt" "Jeff")
   ("Peter" "Paul" "Mary")
   ("To our parents" "Mother Theresa" "God")
   ("pastrami" "ham and cheese" "peanut butter and jelly" "tuna")
   ("recycle tired, old phrases" "ponder big, happy thoughts")
   ("recycle tired, old phrases" 
      "ponder big, happy thoughts" 
      "sleep and dream peacefully") )

(de commifySeries (Lst)
   (ifn (cddr Lst)
      (glue " and " Lst)
      (glue (if (find '((S) (sub? "," S)) Lst) "; " ", ")
         (conc
            (head -1 Lst)
            (cons (pack "and " (last Lst))) ) ) ) )

(for L Lists
   (prinl "The list is: " (commifySeries L) ".") )

(bye)

#-----------------------------
The list is: just one thing.
The list is: Mutt and Jeff.
The list is: Peter, Paul, and Mary.
The list is: To our parents, Mother Theresa, and God.
The list is: pastrami, ham and cheese, peanut butter and jelly, and tuna.
The list is: recycle tired, old phrases and ponder big, happy thoughts.
The list is: recycle tired, old phrases; ponder big, happy thoughts; and sleep and dream peacefully.
#-----------------------------

Changing Array Size

#-----------------------------
(de whatAboutThatArray ()
   (prinl "The array now has " (length People) " elements.")
   (prinl "Element #4 is `" (get People 4) "'.") )

(de People
   Crosby Stills Nash Young )

: (whatAboutThatArray)
The array now has 4 elements.
Element #4 is `Young'.
#-----------------------------
(con (tail 2 People))

: (whatAboutThatArray)
The array now has 3 elements.
Element #4 is `'.
#-----------------------------
(setq People (need -10000 People))

: (whatAboutThatArray)
The array now has 10000 elements.
Element #4 is `'.
#-----------------------------

Doing Something with Every Element in a List

#-----------------------------
(for Item List
   (doSomething Item) )
#-----------------------------
(for User BadUsers
   (complain User) )
#-----------------------------
(for User AllUsers
   (let DiskSpace (getUsage User)
      (when (> DiskSpace MAX_QUOTA)
         (complain User) ) ) )
#-----------------------------
(in '(who)
   (while (line T)
      (and (sub? "tchrist" @) (prinl @)) ) )
#-----------------------------
(until (eof)
   (prinl (glue " " (flip (split (line) " ")))) )
#-----------------------------
(for Item Array
   (prinl "i = " Item) )
#-----------------------------
(setq Array (1 2 3))
(map dec Array)

: Array
-> (0 1 2)
#-----------------------------

Iterating Over an Array by Reference

#-----------------------------
# iterate over elements of list in $ARRAYREF
(map
   '((L)
      (foo (car L))  # Do something with the element
      (set L) )      # Modify an element (destructively)
   List )

(for I (length List)
   (doSomethingWith (get List I)) )
#-----------------------------
(setq
   Fruits '(Apple Blackberry)
   FruitRef 'Fruits )

: (for Fruit (val FruitRef)
   (prinl Fruit " tastes good in a pie.") )
Apple tastes good in a pie.
Blackberry tastes good in a pie.
#-----------------------------

Extracting Unique Elements from a List

#-----------------------------
: (let Uniq NIL
   (for Item '(a b c b c d c d e d e f)
      (unless (memq Item Uniq)
         (push 'Uniq Item) ) )
   Uniq )
-> (f e d c b a)
#-----------------------------
: (let Seen NIL
   (for Item '(a b c b c d c d e d e f)
      (accu 'Seen Item 1) )
   Seen )
-> ((f . 1) (e . 2) (d . 3) (c . 3) (b . 2) (a . 1))
#-----------------------------
: (uniq '(a b c b c d c d e d e f))
-> (a b c d e f)
#-----------------------------
# generate a list of users logged in, removing duplicates
: (in '(who)
   (uniq
      (make
         (while (split (line) " ")
            (link (pack (car @))) ) ) ) )
-> ("tim" "abu" "ben")
#-----------------------------
: (println 'Users 'logged 'in: (sort @))
Users logged in: ("abu" "ben" "tim")
#-----------------------------

Finding Elements in One Array but Not Another

#-----------------------------
# find only elements in A and not in B
: (sect '(a b c d e f) '(a c f h))
-> (a c f)
#-----------------------------
# Using symbol values
: (setq key1 1  key2 2)
-> 2
: key1
-> 1
: key2
-> 2
#-----------------------------
# Using properties
: (put 'Hash 'key1 1)
-> 1
: (put 'Hash 'key2 2)
-> 2
: (get 'Hash 'key1)
-> 1
#-----------------------------
# Using association lists
: (de Hash (key1 . 1) (key2 . 2))
-> Hash
: (assoc 'key1 Hash)
-> (key1 . 1)
: (asoq 'key1 Hash)
-> (key1 . 1)
: (get Hash 'key1)
-> 1
#-----------------------------
# Using index tree
: (idx 'Hash '(key1 . 1) T)
-> NIL
: (idx 'Hash '(key2 . 2) T)
-> NIL
: (lup Hash 'key1)
-> (key1 . 1)
#-----------------------------

Computing Union, Intersection, or Difference of Unique Lists

#-----------------------------
(setq
   A (1 3 5 6 7 8)
   B (2 3 5 7 9) )
#-----------------------------
# Union
: (uniq (append A B))
-> (1 3 5 6 7 8 2 9)
#-----------------------------
# Intersection
: (sect A B)
-> (3 5 7)
#-----------------------------
# Difference
: (diff A B)
-> (1 6 8)
#-----------------------------

Appending One Array to Another

#-----------------------------
(setq
   Members '(Time Flies)
   Initiates '(An Arrow) )
#-----------------------------
: (append Members Initiates)  # Non-destructive
-> (Time Flies An Arrow)
#-----------------------------
: (conc Members Initiates)  # Destructive
-> (Time Flies An Arrow)
# 'Members' is now (Time Flies An Arrow)
#-----------------------------
: (insert 3 Members 'Like)  # Non-destructive
-> (Time Flies Like An Arrow)
#-----------------------------
: (set Members 'Fruit)  # Destructive
-> Fruit
: (set (tail 1 Members) 'Banana)
-> Banana
: Members
-> (Fruit Flies An Banana)
#-----------------------------

Reversing an Array

#-----------------------------
(reverse List)  # Non-destructive
#-----------------------------
(flip List)  # Destructive
#-----------------------------
: (sort (2 8 3 7 5 9 6))
-> (2 3 5 6 7 8 9)
: (by - sort (2 8 3 7 5 9 6))
-> (9 8 7 6 5 3 2)
#-----------------------------
: (flip (sort '(a 3 1 (1 2 3) d b 4 T NIL (a b c) (x y z) c 2)))
-> (T (x y z) (a b c) (1 2 3) d c b a 4 3 2 1 NIL)
#-----------------------------

Processing Multiple Elements of an Array

#-----------------------------
# remove N elements from front of List
: (setq List '(a b c d e f g))
-> (a b c d e f g)
: (cut 3 'List)
-> (a b c)
: List
-> (d e f g)
#-----------------------------
# remove N elements from end of List
: (setq List '(a b c d e f g))
-> (a b c d e f g)
: (tail 3 List)
-> (e f g)
: (con (nth List 4))
-> NIL
: List
-> (a b c d)
#-----------------------------
(setq
   Friends '(Peter Paul Mary Jim Tim)
   This (pop 'Friends)
   Thas (pop 'Friends) )

: This
-> Peter
: That
-> NIL
: Friends
-> (Mary Jim Tim)
#-----------------------------
(setq
   Beverages '(Dew Jolt Cola Sprite Fresca)
   Pair (tail 2 Beverages)
   Beverages (head 3 Beverages) )

: Pair
-> (Sprite Fresca)
: Beverages
-> (Dew Jolt Cola)
#-----------------------------

Finding the First List Element That Passes a Test

#-----------------------------
(with
   (find
      '((This) (== 'engineer (: category)))
      Employees )
   (prinl "Highest paid engineer is: " (: name))  )
#-----------------------------

Finding All Elements in an Array Matching Certain Criteria

#-----------------------------
(de Nums 84598 4439223 248749 2488711 233716 3375644 211118)

: (filter '((N) (> N 1000000)) Nums)
-> (4439223 2488711 3375644)
#-----------------------------
: (filter > Nums (1000000 .))
-> (4439223 2488711 3375644)
#-----------------------------
(filter '((This) (== 'Engineer (: position))) Employees)
#-----------------------------

Sorting an Array Numerically

#-----------------------------
# Pids is an unsorted array of process IDs
(sort Pids)
#-----------------------------
# Descending sort
: (flip (sort (4 19 8 4)))
-> (19 8 4 4)

: (sort (4 19 8 4) >)
-> (19 8 4 4)

: (by - sort (4 19 8 4))
-> (19 8 4 4)
#-----------------------------

Sorting a List by Computable Field

#-----------------------------
: (by cdr sort '((4 . 7) (19 . 3) (8 . 1) (4 . 2)))   # (recommended)
-> ((8 . 1) (4 . 2) (19 . 3) (4 . 7))

: (sort                                               # (slower and bigger)
   '((4 . 7) (19 . 3) (8 . 1) (4 . 2))
   '((X Y) (> (cdr Y) (cdr X))) )
-> ((8 . 1) (4 . 2) (19 . 3) (4 . 7))
#-----------------------------
(for This (by '((This) (: name)) sort Employees)
    (prinl (: name) " earns $" (: salary)) )
#-----------------------------
(by '((This) (cons (: name) (: age))) sort Employees)
#-----------------------------
(by '((S) (cadr (chop S))) sort Names)
#-----------------------------
(by length sort Strings)
#-----------------------------
(sort
   (in "/etc/passwd"
      (make
         (while (split (line) ":")
            (link (mix @ 4 3 1)) ) ) ) )
#-----------------------------

Implementing a Circular List

#-----------------------------
: (circ 'a)
-> (a .)

: (circ 'a 'b 'c)
-> (a b c .)

: (rot @)
-> (c a b .)
#-----------------------------

Randomizing an Array

#-----------------------------
(by '(NIL (rand)) sort Lst)  # OK
#-----------------------------

Program: words

#-----------------------------
# download the following standalone program
#!/usr/bin/picolisp /usr/lib/picolisp/lib.l
# words - gather lines, present in columns

(setq
   Data (in NIL
      (make
         (until (eof)
            (link (line T)) ) ) )
   Maxlen (inc (length (maxi length Data)))
   Cols (max (/ (or (format (sys "COLUMNS")) 80) Maxlen) 1)
   Rows (/ (+ (length Data) Cols) Cols)
   Data (make (while Data (link (cut Rows 'Data)))) )

(while (find bool Data)
   (map
      '((D) (space (- Maxlen (length (prin (pop D))))))
      Data )
   (prinl) )

(bye)

#-----------------------------
#-----------------------------
(de permute (Lst)
   (ifn (cdr Lst)
      (cons Lst)
      (mapcan
         '((X)
            (mapcar
               '((Y) (cons X Y))
               (permute (delete X Lst)) ) )
         Lst ) ) )

: (mapc println (permute '(man bites dog)))
(man bites dog)
(man dog bites)
(bites man dog)
(bites dog man)
(dog man bites)
(dog bites man)
#-----------------------------
(de factorial (N)
   (apply * (range 1 N)) )

: (for N 15 (tab (-20 -10) N (factorial N)))
1                   1
2                   2
3                   6
4                   24
5                   120
6                   720
7                   5040
8                   40320
9                   362880
10                  3628800
11                  39916800
12                  479001600
13                  6227020800
14                  87178291200
15                  1307674368000

: (factorial 500)
-> 12201368259911100687...00000000000000000000
: (length @)
-> 1135
#-----------------------------
# download the following standalone program
#!/usr/bin/picolisp /usr/lib/picolisp/lib.l

(load "@lib/simul.l")  # For 'permute' function

(in NIL
   (until (eof)
      (for F (permute (split (line) " "))
         (prinl (glue " " F)) ) ) )

(bye)

#-----------------------------

Program: permute