list-helpers.scm 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. (library (list-helpers)
  2. (export flatten
  3. make-list
  4. split-off-n
  5. split-into-n-sized-segments
  6. split-at
  7. split-into-segments
  8. split-into-n-segments)
  9. (import
  10. (except (rnrs base) let-values map error)
  11. (only (guile)
  12. lambda* λ
  13. remainder
  14. round
  15. simple-format)
  16. ;; receive form
  17. (srfi srfi-8))
  18. (define flatten
  19. (λ (lst)
  20. (cond [(null? lst) '()]
  21. [(pair? lst)
  22. (append (flatten (car lst))
  23. (flatten (cdr lst)))]
  24. [else
  25. (list lst)])))
  26. (define make-list
  27. (λ (val count)
  28. (cond
  29. [(> count 0)
  30. (cons val (make-list val (- count 1)))]
  31. [else '()])))
  32. (define split-off-n
  33. (λ (lst n)
  34. "Take a list LST and split off the first N elements. Return
  35. 2 values: The split off part and the remaining part of the
  36. list LST."
  37. (let iter ([lst° lst]
  38. [counter 0]
  39. [cont
  40. (λ (acc-split-off rem-lst)
  41. (values acc-split-off rem-lst))])
  42. (cond
  43. [(null? lst°)
  44. (cont '() lst°)]
  45. [(= counter n)
  46. (cont '() lst°)]
  47. [else
  48. (iter (cdr lst°)
  49. (+ counter 1)
  50. (λ (new-tail rem-lst)
  51. (cont (cons (car lst°) new-tail)
  52. rem-lst)))]))))
  53. (define split-into-n-sized-segments
  54. (λ (lst n)
  55. (cond
  56. [(null? lst) '()]
  57. [else
  58. (receive (split-off-part remaining-list)
  59. (split-off-n lst n)
  60. (cons split-off-part
  61. (split-into-n-sized-segments remaining-list n)))])))
  62. (define split-at
  63. (λ (lst pred)
  64. "Each element of LST is checked using the predicate. If the
  65. predicate is satisfied for an element, then that element
  66. will be seen as the separator. Return 2 values: The split
  67. off part and the remaining part of the list LST."
  68. (let iter ([lst° lst]
  69. [index° 0]
  70. [cont
  71. (λ (acc-split-off rem-lst)
  72. (values acc-split-off rem-lst))])
  73. (cond
  74. [(null? lst°)
  75. (cont '() lst°)]
  76. [(pred (car lst°) index°)
  77. (cont '() (cdr lst°))]
  78. [else
  79. (iter (cdr lst°)
  80. (+ index° 1)
  81. (λ (new-tail rem-lst)
  82. (cont (cons (car lst°) new-tail)
  83. rem-lst)))]))))
  84. (define split-into-segments
  85. (λ (lst pred)
  86. "Split the list LST into segments based on a predicate for
  87. an element being a separator or not. Each element is checked
  88. using the predicate. If the predicate is satisfied for an
  89. element, then that element will be seen as a separator and
  90. will not be part of the resulting segments."
  91. (cond
  92. [(null? lst) '()]
  93. [else
  94. (receive (split-off-part remaining-list) (split-at lst pred)
  95. (cons split-off-part
  96. (split-into-segments remaining-list pred)))])))
  97. (define split-into-n-segments
  98. (λ (lst n)
  99. "Try to split list LST into N segments. The function tries
  100. to make the segments as evenly sized as possible."
  101. (let ([chunk-size (round (/ (length lst) n))])
  102. (let iter ([lst° lst] [counter 0])
  103. (cond
  104. [(= counter (- n 1)) (list lst°)]
  105. [(and (< counter n) (null? lst°))
  106. (cons '() (iter lst° (+ counter 1)))]
  107. [(null? lst°) '()]
  108. [else
  109. (receive (split-off-part remaining-list) (split-off-n lst° chunk-size)
  110. (cons split-off-part
  111. (iter remaining-list (+ counter 1))))]))))))