#duplicates #scheme #racket #transitive-closure
#дубликаты #схема #racket #транзитивное закрытие
Вопрос:
Эта функция должна возвращать транзитивное замыкание L. Для примеров:
(Transitive-Closure'((a b) (b c) (a c))) ---> '((a b) (b c) (a c))
(Transitive-Closure'((a a) (b b) (c c))) ---> '((a a) (b b) (c c))
(Transitive-Closure'((a b) (b a))) ---> '((a b) (b a) (a a) (b b)))
(Transitive-Closure'((a b) (b a) (a a)))---> '((a b) (b a) (a a) (b b))
(Transitive-Closure'((a b) (b a) (a a) (b b)))---> '((a b) (b a) (a a) (b b))
(Transitive-Closure'())---> '()
Вот что у меня есть в Racket:
(define (Transitive-Closure L)
(apply append
; Iterate over each pair (a b) in L,
(map (lambda (x)
;Iterate over each pair (c d) in L,
(map (lambda (y)
(let ([a (car x)]
[b (cadr x)]
[c (car y)]
[d (cadr y)])
;if b equal to c, and (a d) does not exist in L, it will add (a d) to L . Otherwise, return L.
(if (and (eq? b c) (not (member (list a d) L)))
(list a d)
(append x))))L)) L)))
Мой код работает только тогда, когда он не является транзитивным. Как я могу изменить свой код, чтобы избежать возврата повторяющихся пар, когда он транзитивный?
Например, мой вывод:
;This is wrong. It should return '((a b)(b c)(a c))
(Transitive-Closure '((a b)(b c)(a c))) ---> '((a b) (a b) (a b) (b c) (b c) (b c) (a c) (a c) (a c))
; This is right.
(Transitive-Closure '((a b)(b a)))---> '((a b) (a a) (b b) (b a))
Комментарии:
1. Ну, вы могли бы использовать
remove-duplicates
, чтобы избавиться от избыточных элементов…2. Алгоритм в любом случае неверен — наверняка вам понадобится некоторая рекурсия, а не просто два вызова map. Выясните это, прежде чем беспокоиться о дубликатах. Например, рассмотрим
((a b) (b c) (c d))
. Это должно быть включено(a d)
в результат, но ваша функция, как написано, не будет включать его.3. Вы добавляете
x
каждый раз, когда условие ложно, что может произойти более одного раза.
Ответ №1:
Это не проблема, это проблема, потому что вы не изменяете список на месте, вы сокращаете список до одного элемента. map
foldr
Этот элемент оказывается a list
, но важно, что список может быть меньше, чем может вернуть map. Также вы можете проверить, следует ли добавлять или нет в другом if
операторе, основываясь на том, существует ли пара в нашем аккумуляторе.
Это работает, если порядок не имеет значения (я предполагаю, что вам просто нужен набор, дайте мне знать, если это не так)
(define (Transitive-Closure L)
; Iterate over each pair (a b) in L,
(foldr (lambda (x transitive-pairs)
;Iterate over each pair (c d) in L,
(foldr (lambda (y sofar)
(let ([a (car x)]
[b (cadr x)]
[c (car y)]
[d (cadr y)])
;if b equal to c, and (a d) does not exist in L, it will add (a d) to L . Otherwise, return L.
(cond [(and (eq? b c) (not (member (list a d) L))) (cons (list a d) sofar)]
[(not (member x sofar)) (cons x sofar)]
[else sofar])))
transitive-pairs L)) '() L))
(check-expect (Transitive-Closure '((a b) (b c) (a c))) '((a b) (b c) (a c)))
(check-expect (Transitive-Closure '((a a) (b b) (c c))) '((a a) (b b) (c c)))
(check-expect (Transitive-Closure '((a b) (b a))) '((a b) (a a) (b b) (b a)))
(check-expect (Transitive-Closure '((a b) (b a) (a a))) '((a b) (b b) (b a) (a a)))
(check-expect (Transitive-Closure '((a b) (b a) (a a) (b b))) '((a b) (b a) (a a) (b b)))