3

How do I implement a program in Scheme taking the elements of a given list and returning a new list where the elements are random gatherings of the previous list? I would like it to work for any length. For example:

Input: '(a e i o u), output: '((a e) (i o) (u)) for length 2.

My attempts (making use of for/list) are being clumsy and based on recursion. I have divided the tasks as suggested by Óscar:

  1. Select n elements randomly from a list l:

    (define (pick-n-random l n)
      (take (shuffle l) n))
    
  2. Remove a list l2 from a list l1:

    (define (cut l1 l2)
      (cond ((null? l1)
             '())
            ((not (member (car l1) l2))
             (cons (car l1) (cut (cdr l1) l2)))
            (else
             (cut (cdr l1) l2))))
    

Then, and that is my problem: how do I recurse over this process to get the intended program? Should I use for/list to paste all sublists got by this process 1. and 2.?

7
  • Which variant of Scheme are you using? Is it R6RS-compatible, R5RS-compatible, Racket, or something else? Commented Nov 16, 2018 at 22:15
  • I am running "mzscheme" in a terminal as suggested here: stackoverflow.com/questions/1175977/…
    – gibarian
    Commented Nov 16, 2018 at 22:18
  • Wait, I just realized that your sample output is not randomized. What do you want to randomize, the contents (as I did in my answer) or the length of the sublists? Commented Nov 16, 2018 at 22:53
  • 1
    The content, as you did. Thank you.
    – gibarian
    Commented Nov 16, 2018 at 22:57
  • Ok then, it's fine :) . You're welcome! Commented Nov 16, 2018 at 22:59

1 Answer 1

5

It's easier if we split the problem into chunks. First, let's write a couple of procedures that will allow us to take or drop n elements from a list, with appropriate results if there are not enough elements left in the list (if not for this, we could have used the built-in take and drop):

(define (take-up-to lst n)
  (if (or (<= n 0) (null? lst))
      '()
      (cons (car lst) (take-up-to (cdr lst) (sub1 n)))))

(define (drop-up-to lst n)
  (if (or (<= n 0) (null? lst))
      lst
      (drop-up-to (cdr lst) (sub1 n))))

With the above two procedures in place, it's easy to create another procedure to group the elements in a list into n-sized sublists:

(define (group lst n)
  (if (null? lst)
      '()
      (cons (take-up-to lst n)
            (group (drop-up-to lst n) n))))

Finally, we combine our grouping procedure with shuffle, which randomizes the contents of the list:

(define (random-groups lst n)
  (group (shuffle lst) n))

It works as expected:

(random-groups '(a e i o u) 2)
=> '((e a) (u i) (o))
4
  • Thank you. My approach was different and entailed a sort of recursion I couldn't solve: 1. take a random group of elements 2. cut the list removing this first group and 3. recurse over this process. I had 1. and 2. working correctly but failed on 3.
    – gibarian
    Commented Nov 16, 2018 at 22:59
  • Any suggestion to do it recursively with my idea?
    – gibarian
    Commented Nov 16, 2018 at 23:20
  • Well, you should edit your post and add the code as part of the question. But it's basically the same as my approach: randomize the list first, then take chunks of the right size. The trick is to split the problem in smaller parts, and in each one focus on a single problem. Commented Nov 16, 2018 at 23:23
  • Ok, I will try on my own and see.
    – gibarian
    Commented Nov 16, 2018 at 23:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.