在方案中随机抽取元素组

时间:2018-11-16 22:12:08

标签: functional-programming scheme lisp

我如何在Scheme中实现一个程序,该程序采用给定列表的元素并返回一个新列表,其中的元素是前一个列表的随机集合?我希望它可以工作任何长度。例如:

输入:'(a e i o u),输出:'((a e) (i o) (u)),长度为2。

我的尝试(使用for / list)很笨拙,并且基于递归。我按照Óscar的建议划分了任务:

  1. 从列表l中随机选择n个元素:

    (define (pick-n-random l n)
      (take (shuffle l) n))
    
  2. 从列表l1中删除列表l2:

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

然后,这就是我的问题:如何在此过程中递归以获得所需的程序?我是否应该使用for/list粘贴此过程1.和2.获得的所有子列表?

1 个答案:

答案 0 :(得分:4)

将问题分成多个部分会更容易。首先,让我们编写一些过程,这些过程将允许我们从列表中取出或删除n元素,如果列表中没有足够的元素,则可以得到适当的结果(如果不是,则可以使用内置takedrop):

(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))))

有了上述两个过程,就很容易创建另一个过程来将列表中的元素分组为n个大小的子列表:

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

最后,我们将分组过程与shuffle结合使用,这会随机化列表的内容:

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

它按预期工作:

(random-groups '(a e i o u) 2)
=> '((e a) (u i) (o))