list-helpers.scm 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. (library (list-helpers)
  2. (export remove-consecutive-duplicates
  3. take-indices
  4. take-range
  5. unique)
  6. (import (except (rnrs base) error)
  7. (only (guile)
  8. lambda* λ
  9. sort)
  10. ;; lists
  11. (srfi srfi-1)
  12. ;; function contracts
  13. (contract)
  14. (ice-9 exceptions))
  15. (define-with-contract remove-consecutive-duplicates
  16. (require (pair? lst)
  17. (procedure? eq-test))
  18. (ensure (pair? <?>))
  19. (lambda* (lst #:key (eq-test eq?))
  20. "Remove consecutive duplicates with regards to EQ-TEST from LST."
  21. (cons (car lst)
  22. (let iter ([lst° (cdr lst)] [prev (car lst)])
  23. (cond
  24. [(null? lst°) '()]
  25. [(eq-test (car lst°) prev)
  26. (iter (cdr lst°) prev)]
  27. [else
  28. (cons (car lst°)
  29. (iter (cdr lst°)
  30. (car lst°)))])))))
  31. (define-with-contract unique
  32. (require (pair? lst)
  33. (procedure? less))
  34. (ensure (pair? lst))
  35. (lambda* (lst #:key (eq-test eq?) (less <))
  36. "Return a list of unique elements of LST. Depends on LESS being
  37. suitable to compare elements of LST to sort LST, before duplicates are
  38. removed from it. EQ-TEST can be specified to check, whether elements
  39. are equal."
  40. (remove-consecutive-duplicates (sort lst less)
  41. #:eq-test eq-test)))
  42. (define-with-contract take-indices
  43. (require (>= (car indices) 0)
  44. (integer? (car indices)))
  45. (ensure (or (null? <?>)
  46. (pair? <?>)))
  47. (λ (lst indices)
  48. "Take elements at the indices INDICES from LST and return them as a
  49. new list."
  50. (let iter ([lst° lst]
  51. [indices° (unique indices #:eq-test = #:less <)]
  52. [index° 0])
  53. (cond
  54. [(null? indices°) '()]
  55. [(= (car indices°) index°)
  56. (cons (car lst°)
  57. (iter (cdr lst°)
  58. (cdr indices°)
  59. (+ index° 1)))]
  60. [else
  61. (iter (cdr lst°)
  62. indices°
  63. (+ index° 1))]))))
  64. (define-with-contract take-range
  65. (require (integer? start)
  66. (integer? end)
  67. (>= start 0)
  68. (<= start end)
  69. (or (null? lst)
  70. (pair? lst)))
  71. (ensure (or (null? <?>)
  72. (pair? <?>)))
  73. (λ (lst start end)
  74. "Take a range of elements from LST. The range starts at index START
  75. and ends at index END."
  76. (let iter ([lst° lst] [index° 0])
  77. (cond
  78. [(null? lst) '()]
  79. [(= index° start)
  80. (guard (con [(eq? (exception-kind con) 'wrong-type-arg)
  81. (raise-exception
  82. (make-exception
  83. (make-exception-with-message "out of bounds index")
  84. (make-exception-with-irritants (list lst start end))
  85. (make-exception-with-origin 'take-range)))])
  86. (take lst° (+ (- end start) 1)))]
  87. [else
  88. (iter (cdr lst°)
  89. (+ index° 1))])))))