Как взять часть списка (подсписка) в схеме?

Учитывая список, как мне выбрать новый список, содержащий фрагмент исходного списка (с учетом смещения и количества элементов)?

РЕДАКТИРОВАТЬ:

Пока хорошие предложения. Не указано ли что-то в одном из SRFI? Это кажется очень фундаментальной вещью, поэтому я удивлен, что мне нужно реализовать ее в пользовательской среде.


person troelskn    schedule 20.09.2008    source источник
comment
Я просто хочу порекомендовать ответ Натана Сандерса, это определенно лучшее использование SRFI, чем другие материалы. Кроме того, это был бы ответ, который я бы написал. :-)   -  person Chris Jester-Young    schedule 10.10.2008


Ответы (5)


Следующий код сделает то, что вы хотите:

(define get-n-items
    (lambda (lst num)
        (if (> num 0)
            (cons (car lst) (get-n-items (cdr lst) (- num 1)))
            '()))) ;'

(define slice
    (lambda (lst start count)
        (if (> start 1)
            (slice (cdr lst) (- start 1) count)
            (get-n-items lst count))))

Пример:

> (define l '(2 3 4 5 6 7 8 9)) ;'
()
> l
(2 3 4 5 6 7 8 9)
> (slice l 2 4)
(3 4 5 6)
> 
person dsm    schedule 20.09.2008
comment
В get-n-items есть опечатка — else-часть формы if нуждается в кавычках. Вы можете отредактировать это? - person troelskn; 20.09.2008

Как ни странно, slice не поставляется с SRFI-1, но вы можете это сделать короче, используя take и drop SRFI-1:

(define (slice l offset n)
  (take (drop l offset) n))

Я думал, что одно из расширений, которые я использовал со Scheme, например, библиотека PLT Scheme или Swindle, будет иметь это встроенное, но, похоже, это не так. Он даже не определен в новых библиотеках R6RS.

person Nathan Shively-Sanders    schedule 23.09.2008
comment
Имейте в виду, что с этим ответом вы не можете выполнить (slice '(1 2 3 4 5 6 7 8 9 0) 3 9), потому что он исчерпает список. На самом деле вам нужно передать ему список смещения от начала и длины конечного вместо двух смещений от нуля. Вы также не можете сделать (slice l 3 -4) (что, по мнению пользователя Python, означает взять все, начиная с третьего и заканчивая четвертым элементом списка l). Реальная функция среза была бы немного сложнее. - person Inaimathi; 20.05.2010
comment
Вы думаете о срезе Python, который использует offset1, offset2. Для подхода смещения, количества элементов это правильный ответ: возьмите 9 элементов, начиная с 3-го должно дать вам меньше 9, если список закончится. (Лично я считаю, что подход Python лучше, но вопрос не в этом.) - person Nathan Shively-Sanders; 20.05.2010

Вы можете попробовать эту функцию:

подпоследовательность начало последовательности и необязательно конец

Параметр start — это ваше смещение. Параметр end можно легко превратить в количество элементов для захвата, просто добавив начало + количество элементов.

Небольшой бонус в том, что subseq работает со всеми последовательностями, включая не только списки, но также строки и векторы.

Редактировать: кажется, что не все реализации lisp имеют subseq, хотя он отлично справится с этой задачей, если он у вас есть.

person Josh Gagnon    schedule 22.09.2008
comment
Является ли subseq функцией CL? По крайней мере, он не является частью PLT-Scheme. - person troelskn; 23.09.2008
comment
Он есть у Гоша: practical-scheme.net/wiliki/arcxref?subseq. не знаю о других. - person dsm; 23.09.2008
comment
Странный. Я читал об этом Paradigms of AI, и он был представлен как часть стандарта. Наверное, я не уверен, какой из стандартов. :P Извините за это. - person Josh Gagnon; 23.09.2008

Вот моя реализация slice, которая использует правильный хвостовой вызов

(define (slice a b xs (ys null))
  (cond ((> a 0) (slice (- a 1) b (cdr xs) ys))
        ((> b 0) (slice a (- b 1) (cdr xs) (cons (car xs) ys)))
        (else (reverse ys))))

(slice 0 3 '(A B C D E F G)) ;=> '(A B C)
(slice 2 4 '(A B C D E F G)) ;=> '(C D E F)
person Mulan    schedule 21.02.2016

Попробуйте что-то вроде этого:

    (define (slice l offset length)
      (if (null? l)
        l
        (if (> offset 0)
            (slice (cdr l) (- offset 1) length)
            (if (> length 0)
                (cons (car l) (slice (cdr l) 0 (- length 1)))
                '()))))
person Martin Cote    schedule 20.09.2008