list.scm 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. (define-module (utils list))
  2. (use-modules
  3. ;; SRFI 1 for additional list procedures
  4. (srfi srfi-1)
  5. ;; SRFI-27 for random number utilities
  6. (srfi srfi-27)
  7. (utils string)
  8. (utils collections)
  9. (utils random))
  10. (define-public map*
  11. (lambda (proc lst)
  12. (cond [(null? lst) '()]
  13. [(pair? (car lst))
  14. (cons (map* proc (car lst))
  15. (map* proc (cdr lst)))]
  16. [else
  17. (cons (proc (car lst))
  18. (map* proc (cdr lst)))])))
  19. (define-public stringify*
  20. (lambda (lst)
  21. (map* stringify lst)))
  22. (define-public apply-multiple
  23. (lambda (procs val)
  24. (cond
  25. [(null? procs) val]
  26. [else
  27. (apply-multiple (cdr procs) ((car procs) val))])))
  28. (define-public fisher-yates-shuffle
  29. (lambda* (lst #:key (seed #f))
  30. (let ([get-rand-int (make-random-integer-generator #:seed seed)]
  31. [lst-as-vec (list->vector lst)])
  32. (let loop
  33. ;; Build up a list as result, which contains the elements of the
  34. ;; original list.
  35. ([result '()]
  36. ;; The list needs to have the same amount of elements as the original
  37. ;; list.
  38. [elements-to-pick (vector-length lst-as-vec)])
  39. (cond
  40. [(zero? elements-to-pick) result]
  41. [else
  42. (let*
  43. ;; Get a random number. [0,limit)
  44. ;; example: limit = 10, rand-int = 9
  45. ([rand-int (get-rand-int elements-to-pick)]
  46. ;; Get randomly an existing value from the vector of values, which
  47. ;; was created from the given list.
  48. ;; example: val = 9th value
  49. [val (vector-ref lst-as-vec rand-int)])
  50. ;; At the position, where we go the value from, set another value,
  51. ;; overwriting the value we already picked. Overwrite it with the
  52. ;; value, which otherwise cannot be picked any longer, as we count
  53. ;; down the elements-to-pick and lower the limit for the random
  54. ;; integer generation.
  55. ;; There are 2 cases here:
  56. ;; Case 1: The picked value was already the value at the position (-
  57. ;; elements-to-pick 1). In this case, it does not matter, that the
  58. ;; value can not be picked again and we only write it back to its own
  59. ;; position.
  60. ;; Case 2: The picked value was any value at an index lower than (-
  61. ;; elements-to-pick 1). In this case, we keep the possibility, that
  62. ;; the value at (- elements-to-pick 1) can be picked in the next
  63. ;; iteration, by writing that value to the position of the picked
  64. ;; value.
  65. ;; This way, as the limit for random integers gets lower, all values
  66. ;; will eventually be picked.
  67. ;; Save the value at the highest possible index, so that it can be
  68. ;; picked next iteration. Overwrite already picked value.
  69. (vector-set! lst-as-vec
  70. rand-int
  71. ;; Take the value at the highest index.
  72. (vector-ref lst-as-vec
  73. (- elements-to-pick 1)))
  74. (loop
  75. ;; Add the randomly chosen value to the list of values.
  76. (cons val result)
  77. ;; Count down the elements, which we still need to pick.
  78. (- elements-to-pick 1)))])))))
  79. (define-public list-reduce (make-reducer car cdr null?))
  80. (define-public accumulate
  81. (lambda (op initial seq)
  82. (if (null? seq)
  83. initial
  84. ;; Is is getting the first element of the sequence, but to calculate the
  85. ;; result, it requires, that the result for the rest of the sequence is
  86. ;; calculated. With strict evaluation order, this means, that the first
  87. ;; actual application of `op` is going to happen with the last element
  88. ;; of the sequence and the given `initial` value.
  89. (op (car seq)
  90. (accumulate op initial (cdr seq))))))
  91. (define-public fold-right
  92. (lambda (op initial seq)
  93. ;; folding right means to start folding on the right and progress towards
  94. ;; the left side, assuming a reading direction and display direction of the
  95. ;; sequence from left to right.
  96. (accumulate op initial seq)))
  97. (define-public fold-left
  98. (lambda (op initial seq)
  99. ;; folding left means to accumulate a result starting by applying the `op`
  100. ;; to the `initial` value and the first element of the sequence, resulting
  101. ;; in an intermediate result and then progressing through the sequence,
  102. ;; always applying `op` to the updated intermediate result and the first
  103. ;; element of the rest of the sequence.
  104. (define (iter result remaining)
  105. (if (null? remaining)
  106. result
  107. (iter (op (car remaining) result)
  108. (cdr remaining))))
  109. (iter initial seq)))
  110. (define-public flatten
  111. (lambda (lst)
  112. (cond
  113. [(null? lst) '()]
  114. [else
  115. (let ([head (car lst)]
  116. [tail (cdr lst)])
  117. (cond
  118. [(pair? head)
  119. (append (flatten head) (flatten tail))]
  120. [else
  121. (cons head (flatten tail))]))])))
  122. (define-public list-range
  123. (lambda (lst start end)
  124. "Get the sub list of a list starting at start and ending at end, including
  125. the start index and excluding the end index: [start, end)."
  126. (cond
  127. [(null? lst) '()]
  128. [else
  129. (take (drop lst start)
  130. (- end start))])))
  131. ;; Procedures not included in Scheme or Guile need to be added. count was added
  132. ;; for porting the code from Racket to Scheme.
  133. (define-public count
  134. (lambda (pred ls)
  135. "Count the elements of the list ls for which the predicate pred returns #t."
  136. (let iter ([remaining ls] [count 0])
  137. (cond
  138. [(null? remaining) count]
  139. [else
  140. (if (pred (car remaining))
  141. (iter (cdr remaining) (+ count 1))
  142. (iter (cdr remaining) count))]))))
  143. #;(define-public list-mean
  144. (lambda (lst)
  145. "Calculate the inexact mean of a list of numbers."
  146. (exact->inexact
  147. (/ (apply + lst)
  148. (length lst)))))
  149. (define-public take-up-to
  150. (lambda (n xs)
  151. "Take the first n elements from the list."
  152. (cond
  153. [(or (zero? n) (null? xs))
  154. '()]
  155. [else
  156. (cons (car xs)
  157. (take-up-to (- n 1) (cdr xs)))])))
  158. (define-public drop-up-to
  159. (lambda (n xs)
  160. "Drop the first n elements from the list xs."
  161. (cond
  162. [(or (= n 0) (null? xs))
  163. xs]
  164. [else
  165. (drop-up-to (- n 1) (cdr xs))])))
  166. (define-public split-into-chunks-of-size-n
  167. (lambda (xs n)
  168. "Split up a list xs into sub lists, which contain at maximum n elements. It
  169. is possible, that the last sub list contains less elements, if the length of the
  170. list is not divisable by n."
  171. (cond
  172. [(null? xs) '()]
  173. [else
  174. (let ([first-chunk (take-up-to n xs)]
  175. [rest (drop-up-to n xs)])
  176. (cons first-chunk (split-into-chunks-of-size-n rest n)))])))
  177. (define-public range
  178. (lambda* (start end #:optional (step 1))
  179. (cond
  180. [(>= start end) '()]
  181. [else
  182. (cons start
  183. (range (+ start step)
  184. end
  185. step))])))