#sorting #scheme #racket
#сортировка #схема #racket
Вопрос:
Проблема
Просто для пояснения: на самом деле речь идет не о сортировке в точном смысле. Мне дана функция (sort-sym lst symbol)
. Функция принимает (listof (listof symbol)) и символ, чтобы превратить его в (list (listof (listof symbol)) (список (список символов))). Простое изложение проблемы здесь не очень помогает, поэтому давайте сразу перейдем к примерам.
Примеры
Для списка
(define example (list
(list 'chocolate 'sweet 'expensive)
(list 'crocodile 'hostile 'big 'heavy)
(list 'brick 'heavy 'red)
(list 'chocolate 'bitter 'dark)))
Если я введу (sort-sym example'chocolate)
, список будет отсортирован таким образом:
(list
(list (list 'chocolate 'sweet 'expensive)
(list 'chocolate 'bitter 'dark))
(list (list 'crocodile 'hostile 'big 'heavy)
(list 'brick 'heavy 'red)))
Если входные данные были (sort-sym example'crocodile)
, то список будет
(list
(list (list 'crocodile 'hostile 'big 'heavy))
(list (list 'chocolate 'sweet 'expensive)
(list 'chocolate 'bitter 'dark)
(list 'brick 'heavy 'red)))
Обратите внимание, что все списки, в которых есть слово «шоколад», помещаются в один список, а все списки, в которых нет этого слова, помещаются в другой список. Порядок в этом случае не имеет значения.
Кроме того: пробел между двумя списками предназначен только для того, чтобы сделать код более понятным.
Код
Так что я немного запутался в этом. Но я попробовал несколько вещей, например, я попробовал использовать filter .
(define (sort-examples lst sym)
(local [(define (sym-equal? other-sym) (symbol=? other-sym sym))]
(cond [(empty? lst) empty]
[else (cons (filter sym-equal? (first lst))
(sort-examples (rest lst) sym))])))
Однако это не очень помогает, поскольку я пытаюсь сохранить списки, а не удалять из них элементы. Могу ли я получить некоторые рекомендации по этому вопросу? Спасибо.
Комментарии:
1. Поддерживает ли racket SRFI-1
partition
? Или смысл упражнения в написании собственной версии?2. Я подозреваю, что смысл этого упражнения в том, чтобы выяснить, насколько проще становится, если вы разделите его на две задачи: «разделение списка на основе предиката» и «определение предиката».
Ответ №1:
Как указано в комментариях, в Racket будет просто использовать partition
встроенную процедуру:
(define (sort-sym lst sym)
(let-values (((match no-match)
(partition (lambda (sl) (symbol=? (first sl) sym))
example)))
(list match no-match)))
Это также можно решить, выполнив две filter
операции, хотя это будет менее эффективно:
(define (sort-sym lst sym)
(list (filter (lambda (sl) (symbol=? (first sl) sym)) lst)
(filter (lambda (sl) (not (symbol=? (first sl) sym))) lst)))
В любом случае это работает так, как ожидалось для приведенных примеров:
(define example
'((chocolate sweet expensive)
(crocodile hostile big heavy)
(brick heavy red)
(chocolate bitter dark)))
(sort-sym example 'chocolate)
=> '(((chocolate sweet expensive) (chocolate bitter dark))
((crocodile hostile big heavy) (brick heavy red)))
(sort-sym example 'crocodile)
=> '(((crocodile hostile big heavy))
((chocolate sweet expensive) (chocolate bitter dark) (brick heavy red)))
Комментарии:
1. Спасибо за ответ. Это действительно помогло. Несмотря на то, что мне разрешено использовать lambda, мне любопытно узнать, есть ли другой вариант, кроме него. Если есть, не могли бы вы кратко объяснить, как это будет работать?
2. Ну, вы могли бы в принципе реализовать свою собственную версию
filter
: процедура, которая получает входной список и возвращает в качестве выходных элементы в списке, которые удовлетворяют условию. Общая идея заключается в том, что вы должны разделить проблему на более мелкие части и написать вспомогательные процедуры для решения каждой части.