123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- (define-module (utils list))
- (use-modules
- ;; SRFI 1 for additional list procedures
- (srfi srfi-1)
- ;; SRFI-27 for random number utilities
- (srfi srfi-27)
- (utils string)
- (utils collections)
- (utils random))
- (define-public map*
- (lambda (proc lst)
- (cond [(null? lst) '()]
- [(pair? (car lst))
- (cons (map* proc (car lst))
- (map* proc (cdr lst)))]
- [else
- (cons (proc (car lst))
- (map* proc (cdr lst)))])))
- (define-public stringify*
- (lambda (lst)
- (map* stringify lst)))
- (define-public apply-multiple
- (lambda (procs val)
- (cond
- [(null? procs) val]
- [else
- (apply-multiple (cdr procs) ((car procs) val))])))
- (define-public fisher-yates-shuffle
- (lambda* (lst #:key (seed #f))
- (let ([get-rand-int (make-random-integer-generator #:seed seed)]
- [lst-as-vec (list->vector lst)])
- (let loop
- ;; Build up a list as result, which contains the elements of the
- ;; original list.
- ([result '()]
- ;; The list needs to have the same amount of elements as the original
- ;; list.
- [elements-to-pick (vector-length lst-as-vec)])
- (cond
- [(zero? elements-to-pick) result]
- [else
- (let*
- ;; Get a random number. [0,limit)
- ;; example: limit = 10, rand-int = 9
- ([rand-int (get-rand-int elements-to-pick)]
- ;; Get randomly an existing value from the vector of values, which
- ;; was created from the given list.
- ;; example: val = 9th value
- [val (vector-ref lst-as-vec rand-int)])
- ;; At the position, where we go the value from, set another value,
- ;; overwriting the value we already picked. Overwrite it with the
- ;; value, which otherwise cannot be picked any longer, as we count
- ;; down the elements-to-pick and lower the limit for the random
- ;; integer generation.
- ;; There are 2 cases here:
- ;; Case 1: The picked value was already the value at the position (-
- ;; elements-to-pick 1). In this case, it does not matter, that the
- ;; value can not be picked again and we only write it back to its own
- ;; position.
- ;; Case 2: The picked value was any value at an index lower than (-
- ;; elements-to-pick 1). In this case, we keep the possibility, that
- ;; the value at (- elements-to-pick 1) can be picked in the next
- ;; iteration, by writing that value to the position of the picked
- ;; value.
- ;; This way, as the limit for random integers gets lower, all values
- ;; will eventually be picked.
- ;; Save the value at the highest possible index, so that it can be
- ;; picked next iteration. Overwrite already picked value.
- (vector-set! lst-as-vec
- rand-int
- ;; Take the value at the highest index.
- (vector-ref lst-as-vec
- (- elements-to-pick 1)))
- (loop
- ;; Add the randomly chosen value to the list of values.
- (cons val result)
- ;; Count down the elements, which we still need to pick.
- (- elements-to-pick 1)))])))))
- (define-public list-reduce (make-reducer car cdr null?))
- (define-public accumulate
- (lambda (op initial seq)
- (if (null? seq)
- initial
- ;; Is is getting the first element of the sequence, but to calculate the
- ;; result, it requires, that the result for the rest of the sequence is
- ;; calculated. With strict evaluation order, this means, that the first
- ;; actual application of `op` is going to happen with the last element
- ;; of the sequence and the given `initial` value.
- (op (car seq)
- (accumulate op initial (cdr seq))))))
- (define-public fold-right
- (lambda (op initial seq)
- ;; folding right means to start folding on the right and progress towards
- ;; the left side, assuming a reading direction and display direction of the
- ;; sequence from left to right.
- (accumulate op initial seq)))
- (define-public fold-left
- (lambda (op initial seq)
- ;; folding left means to accumulate a result starting by applying the `op`
- ;; to the `initial` value and the first element of the sequence, resulting
- ;; in an intermediate result and then progressing through the sequence,
- ;; always applying `op` to the updated intermediate result and the first
- ;; element of the rest of the sequence.
- (define (iter result remaining)
- (if (null? remaining)
- result
- (iter (op (car remaining) result)
- (cdr remaining))))
- (iter initial seq)))
- (define-public flatten
- (lambda (lst)
- (cond
- [(null? lst) '()]
- [else
- (let ([head (car lst)]
- [tail (cdr lst)])
- (cond
- [(pair? head)
- (append (flatten head) (flatten tail))]
- [else
- (cons head (flatten tail))]))])))
- (define-public list-range
- (lambda (lst start end)
- "Get the sub list of a list starting at start and ending at end, including
- the start index and excluding the end index: [start, end)."
- (cond
- [(null? lst) '()]
- [else
- (take (drop lst start)
- (- end start))])))
- ;; Procedures not included in Scheme or Guile need to be added. count was added
- ;; for porting the code from Racket to Scheme.
- (define-public count
- (lambda (pred ls)
- "Count the elements of the list ls for which the predicate pred returns #t."
- (let iter ([remaining ls] [count 0])
- (cond
- [(null? remaining) count]
- [else
- (if (pred (car remaining))
- (iter (cdr remaining) (+ count 1))
- (iter (cdr remaining) count))]))))
- #;(define-public list-mean
- (lambda (lst)
- "Calculate the inexact mean of a list of numbers."
- (exact->inexact
- (/ (apply + lst)
- (length lst)))))
- (define-public take-up-to
- (lambda (n xs)
- "Take the first n elements from the list."
- (cond
- [(or (zero? n) (null? xs))
- '()]
- [else
- (cons (car xs)
- (take-up-to (- n 1) (cdr xs)))])))
- (define-public drop-up-to
- (lambda (n xs)
- "Drop the first n elements from the list xs."
- (cond
- [(or (= n 0) (null? xs))
- xs]
- [else
- (drop-up-to (- n 1) (cdr xs))])))
- (define-public split-into-chunks-of-size-n
- (lambda (xs n)
- "Split up a list xs into sub lists, which contain at maximum n elements. It
- is possible, that the last sub list contains less elements, if the length of the
- list is not divisable by n."
- (cond
- [(null? xs) '()]
- [else
- (let ([first-chunk (take-up-to n xs)]
- [rest (drop-up-to n xs)])
- (cons first-chunk (split-into-chunks-of-size-n rest n)))])))
- (define-public range
- (lambda* (start end #:optional (step 1))
- (cond
- [(>= start end) '()]
- [else
- (cons start
- (range (+ start step)
- end
- step))])))
|