我正在尝试编写一个带有符号和列表的过程,并在给定列表中的每个可能位置插入符号(从而生成列表列表)。我编写了以下定义,我必须实现这些定义:
(define (insert-at pos elmt lst)
(if (empty? lst) (list elmt)
(if (= 1 pos)
(cons elmt lst)
(cons (first lst)
(insert-at (- pos 1) elmt (rest lst))))))
(define (generate-all-pos start end)
(if (= start end)
(list end)
(cons start (generate-all-pos (+ start 1) end))))
1在列表(数字),符号和列表本身中占据一个位置,并在要求的位置插入符号。 2取一个起始位置和一个目标位置(数字),并创建一个带有从开始到目标的数字的排序列表。 到目前为止,我已经得到了这个:
(define (insert-everywhere sym los)
(cond
[(empty? los) (list sym)]
[else (cons (insert-at (first (generate-all-pos (first los)
(first (foldl cons empty los)))) sym los) (insert-everywhere sym (rest los)))
]
)
)
结果是
> (insert-everywhere 'r '(1 2 3))
(list (list 'r 1 2 3) (list 2 'r 3) (list 3 'r) 'r)
所以我实际上设法移动'r'。我对保留列表中的前面成员感到很困惑。也许我错过了一些非常简单的东西,但是我已经盯着代码看了很长时间,这是迄今为止我做过的最干净的结果。任何帮助将不胜感激。
答案 0 :(得分:4)
Óscar López's answer显示了如何根据您已定义的过程执行此操作。我想指出一种方法来执行此操作,以减少输入列表。它使用一个名为revappend
的辅助函数(我从Common Lisp的revappend
中取名)。 revappend
采用列表和尾部,并有效地返回(append (reverse list) tail)
所需的相同内容。
(define (revappend list tail)
(if (null? list)
tail
(revappend (rest list)
(list* (first list) tail))))
> (revappend '(3 2 1) '(4 5 6))
'(1 2 3 4 5 6)
我们对这样一个函数感兴趣的原因是,当我们递减输入列表时,我们可以建立一个我们已经看过的元素列表,但它的顺序是相反的。也就是说,当我们走下(1 2 3 4 5)
时,很容易:{/ p>
rhead tail (revappend rhead (list* item tail))
----------- ----------- -----------------------------------
() (1 2 3 4 5) (r 1 2 3 4 5)
(1) (2 3 4 5) (1 r 2 3 4 5)
(2 1) (3 4 5) (1 2 r 3 4 5)
(3 2 1) (4 5) (1 2 3 r 4 5)
(4 3 2 1) (5) (1 2 3 4 r 5)
(5 4 3 2 1) () (1 2 3 4 5 r)
在每种情况下,(revappend rhead (list* item tail))
都会返回在其中一个位置插入item
的列表。因此,如果我们以相反的顺序构建insert-everywhere
列表,我们就可以用rhead
和tail
以及revappend
来定义results
,并reverse
1}}它在循环结束时。
(define (insert-everywhere item list)
(let ie ((tail list)
(rhead '())
(results '()))
(if (null? tail)
(reverse (list* (revappend rhead (list* item tail)) results))
(ie (rest tail)
(list* (first tail) rhead)
(list* (revappend rhead (list* item tail)) results)))))
(insert-everywhere 'r '(1 2 3))
;=> '((r 1 2 3) (1 r 2 3) (1 2 r 3) (1 2 3 r))
有趣的是,子列表都具有相同的尾部结构。也就是说,子列表共享结构,如下图“图”所示。
;=> '((r 1 2 3) (1 r 2 3) (1 2 r 3) (1 2 3 r))
; ----- +++ o
; +++ o
; o
答案 1 :(得分:1)
insert-everywhere
程序过于复杂,一个简单的map
就可以解决问题。试试这个:
(define (insert-everywhere sym los)
(map (lambda (i)
(insert-at i sym los))
(generate-all-pos 1 (add1 (length los)))))
另请注意,在Racket中存在一个名为range
的过程,因此您无需实现自己的generate-all-pos
:
(define (insert-everywhere sym los)
(map (lambda (i)
(insert-at i sym los))
(range 1 (+ 2 (length los)))))
无论哪种方式,它都按预期工作:
(insert-everywhere 'r '(1 2 3))
=> '((r 1 2 3) (1 r 2 3) (1 2 r 3) (1 2 3 r))