vector-procs.scm 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. (library (vector-procs)
  2. (export vector-filter
  3. vector-union
  4. vector-contains
  5. vector-shuffle
  6. vector-update-elements)
  7. (import (except (rnrs base) vector-map)
  8. (only (guile)
  9. lambda* λ)
  10. (ice-9 exceptions)
  11. ;; SRFIs
  12. ;; srfi-43 for vector procs
  13. (srfi srfi-43)
  14. ;; custom libs
  15. (random-utils)
  16. (iter-utils)))
  17. (define vector-copy-elements!
  18. (λ (source target indices)
  19. "Copy elements from vector SOURCE at INDICES to vector TARGET."
  20. ;; Iteratively copy all elements, which are matching.
  21. (let iter ([remaining-indices indices]
  22. [target-next-ind 0])
  23. (cond
  24. ;; If no more indices are left, return the new vector.
  25. [(null? remaining-indices) target]
  26. [else
  27. ;; Copy over the value from the source vector.
  28. (vector-set! target
  29. target-next-ind
  30. (vector-ref source (car remaining-indices)))
  31. ;; Continue with the rest of the indices.
  32. (iter (cdr remaining-indices)
  33. (+ target-next-ind 1))]))))
  34. (define vector-filter
  35. (λ (pred vec)
  36. "Filter a vector and return the filtered vector."
  37. (define iter
  38. (λ (index entries-found-count indices)
  39. "Iterate over the whole vector from last to first
  40. element, keeping track of elements, for which the predicate
  41. pred is true. Build a list in reverse, which will be in the
  42. order of going from first to last element of the vector,
  43. without the need to reverse it later."
  44. (cond
  45. ;; If the whole vector has been searched for
  46. ;; matching elements, return the indices of
  47. ;; matching elements and the number of matching
  48. ;; elements found.
  49. [(< index 0)
  50. (values indices entries-found-count)]
  51. ;; Otherwise continue iterating over the vector.
  52. [else
  53. (let ([vec-elem (vector-ref vec index)])
  54. (cond
  55. ;; Case for matching elements.
  56. [(pred vec-elem)
  57. (iter (- index 1)
  58. (+ entries-found-count 1)
  59. (cons index indices))]
  60. [else
  61. (iter (- index 1)
  62. entries-found-count
  63. indices)]))])))
  64. (let-values ([(indices entries-found-count)
  65. (iter (- (vector-length vec) 1)
  66. 0
  67. '())])
  68. (vector-copy-elements! vec
  69. (make-vector entries-found-count
  70. 'undefined)
  71. indices))))
  72. (define vector-contains
  73. (lambda* (vec elem #:key (equal-test equal?))
  74. "Check whether the vector contains the given element is
  75. in the given vector under the given equal-test function."
  76. (vector-any (λ (in-vec-item) (equal-test elem in-vec-item))
  77. vec)))
  78. (define vector-union
  79. (lambda* (vec1 vec2 #:key (equal-test equal?))
  80. "Construct a new vector, containing all values of vector
  81. vec1 and and vector vec2, but at most once."
  82. (let ([vec1-len (vector-length vec1)])
  83. (let iter ([index (- (vector-length vec1) 1)]
  84. [result-lst (vector->list vec2)])
  85. (cond
  86. ;; Base case.
  87. [(< index 0)
  88. (list->vector result-lst)]
  89. [else
  90. (let ([elem (vector-ref vec1 index)])
  91. (cond
  92. ;; If the element was already in vec2, do not add
  93. ;; it to the result list.
  94. [(vector-contains vec2 elem #:equal-test equal?)
  95. (iter (- index 1) result-lst)]
  96. ;; If the element was not already in vec2, add it
  97. ;; to the result list.
  98. [else
  99. (iter (- index 1) (cons elem result-lst))]))])))))
  100. (define vector-shuffle
  101. (lambda* (vec #:key (seed #f))
  102. "Shuffle the elements of a given vector and return a
  103. shuffled version of the vector."
  104. (let* ([vec-len (vector-length vec)]
  105. [indices
  106. (if seed
  107. (fisher-yates-shuffle (range 0 vec-len) #:seed seed)
  108. (fisher-yates-shuffle (range 0 vec-len)))]
  109. [new-vec (make-vector vec-len 'undefined)])
  110. (let iter ([remaining-indices indices]
  111. [new-vec-ind 0])
  112. (cond
  113. [(null? remaining-indices)
  114. new-vec]
  115. [else
  116. (vector-set! new-vec
  117. new-vec-ind
  118. (vector-ref vec (car remaining-indices)))
  119. (iter (cdr remaining-indices)
  120. (+ new-vec-ind 1))])))))
  121. (define vector-update-elements
  122. (lambda* (current
  123. update
  124. #:key
  125. (should-update? (λ (elem-base elem-changed) #f))
  126. (update-item (λ (elem-base elem-changed) elem-changed)))
  127. "Update the given CURRENT vector using the given UPDATE
  128. vector. Items are updated depending on
  129. SHOULD-UPDATE?. UPDATE-ITEM performs the actual update of
  130. the elements of CURRENT.
  131. Runtime is O(m * n), where m is the number of elements in
  132. the CURRENT vector and n is the number of elements in the
  133. UPDATE vector."
  134. (define current-length (vector-length current))
  135. (define update-length (vector-length update))
  136. ;; We need map over current elements so that we get a
  137. ;; vector of same length.
  138. (vector-map
  139. (λ (i current-elem)
  140. ;; Inner loop loops over the updates, one by one,
  141. ;; checking if any of the updates applies to the
  142. ;; current element, using should-update?.
  143. (let next-update ([index 0])
  144. (cond
  145. ;; If no update applies to the current element,
  146. ;; simply return the current element.
  147. [(>= index update-length)
  148. current-elem]
  149. ;; Otherwise look at the update element.
  150. [else
  151. (let ([update-elem (vector-ref update index)])
  152. (cond
  153. ;; If the current element should be updated,
  154. ;; make use of the given merge-items procedure
  155. ;; to do so, in a way specified by the caller.
  156. [(should-update? current-elem update-elem)
  157. (update-item current-elem update-elem)]
  158. ;; Otherwise recur. Check if the next update
  159. ;; element might apply.
  160. [else
  161. (next-update (+ index 1))]))])))
  162. current)))