tags:

views:

1268

answers:

6

Given a list, how would I select a new list, containing a slice of the original list (Given offset and number of elements) ?

EDIT:

Good suggestions so far. Isn't there something specified in one of the SRFI's? This appears to be a very fundamental thing, so I'm surprised that I need to implement it in user-land.

+6  A: 

The following code will do what you want:

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

Example:

> (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)
>
dsm
There's a typo in get-n-items - The else-part of the if-form needs a quote. Can you edit that?
troelskn
A: 
(define (sublist list start number)
  (cond ((> start 0) (sublist (cdr list) (- start 1) number))
        ((> number 0) (cons (car list)
                      (sublist (cdr list) 0 (- number 1))))
        (else '())))
Matthias Benkard
A: 

Try something like this:

    (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)))
                '()))))
Martin Cote
+1  A: 

You can try this function:

subseq sequence start &optional end

The start parameter is your offset. The end parameter can be easily turned into the number of elements to grab by simply adding start + number-of-elements.

A small bonus is that subseq works on all sequences, this includes not only lists but also string and vectors.

Edit: It seems that not all lisp implementations have subseq, though it will do the job just fine if you have it.

Josh Gagnon
Is subseq a CL function? It doesn't appear to be part of PLT-Scheme at least.
troelskn
Gauche has it: http://practical-scheme.net/wiliki/arcxref?subseq. don't know about others.
dsm
Weird. I read about it Paradigms of AI and it was presented as part of the standard. I guess I'm not sure which one of the standards. :P Sorry 'bout that.
Josh Gagnon
+2  A: 

Strangely, slice is not provided with SRFI-1 but you can make it shorter by using SRFI-1's take and drop:

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

I thought that one of the extensions I've used with Scheme, like the PLT Scheme library or Swindle, would have this built-in, but it doesn't seem to be the case. It's not even defined in the new R6RS libraries.

Nathan Sanders
Keep in mind that with this answer, you can't do `(slice '(1 2 3 4 5 6 7 8 9 0) 3 9)` because it'll run out of list. You actually have to pass it an offset-from-start and length-of-final-list instead of two offsets from zero. You also can't do `(slice l 3 -4)` (which a python user would expect to mean "take everything from the third to the fourth-to-last element of list l"). A real slice function would be quite a bit more complicated.
Inaimathi
You are thinking of Python slice, which uses offset1, offset2. For the offset, number-of-elements approach, this is the right answer: "take 9 elements starting at the 3rd" *should* give you fewer than 9 if the list runs out. (I personally think Python's approach is better, but that's not what the question is.)
Nathan Sanders
A: 
(define (slice a-list start end)
  (define (slicify n)
    (if (negative? n)
        (+ (length a-list) n)
        n))

  (let* ((s (slicify start))
         (e (slicify end))
         (len (abs (- s e))))
    (take (drop a-list (min s e)) len)))

More complicated than the other attempts, but

>(define l '(1 2 3 4 5 6 7 8 9 0))
l
>(slice l 3 6)
'(4 5 6)
>(slice l 2 -2)
'(3 4 5 6 7 8)
>(slice l -3 -8)
'(3 4 5 6 7)

I'm sure I missed edge cases and other interactions, but this is a bit closer to how python treats slicing. It is sort of surprising that you have to write this yourself instead of having it provided. That said, I've never really found myself slicing very much in Scheme. And when I do, it's typically easier/more semantically accurate to use take, drop and list-ref than actual slicing.

Inaimathi