Reputation: 67
Given a list, and a number, n, I am trying to split a list into two separate lists: one into a list of length n, and the second list being the rest of the original list.
Here is what I have:
(define (part lst i)
(if (> i 0)
(list (append (list (first lst)) (list (part (rest lst) (- i 1)))))
(append lst)))
Where lst is the inputted list, and i is the number. When I input the list '(1 2 3 4) with the number 2, I return an output of: '((1 ((2 (3 4))))) instead of what I want which is '((1 2) (3 4)).
This is for a homework assignment, so it would be much appreciated if someone could just point me in the right direction as to where my problem lies, and because it is a hw assignment, I only am allowed to use the simple racket functions.
EDIT:
When I change the code to:
(define (part lst i)
(if (> i 0)
(append (list (first lst)) (list (part (rest lst) (- i 1))))
(append lst)))
I get an output of '(1 (2 (3 4))).
Upvotes: 2
Views: 10141
Reputation: 235994
Using existing libraries
There's an easy way to solve this problem in Racket, just use the built-in split-at
procedure (also available in the SRFI-1 library). This has the advantage of making a single pass across the input list:
(define (part lst i)
(let-values (((head tail) (split-at lst i)))
(list head tail)))
Another option would be to use Racket's built-in procedures take
and drop
(also available in SRFI-1) - but this will make two passes across the input list:
(define (part lst i)
(list (take lst i)
(drop lst i)))
Implementation from scratch
To build our own solution, we could write a procedure that makes a single pass, like this:
(define (part lst i)
(if (negative? i)
(error "index can't be negative")
(let loop ((lst lst) (acc '()) (i i))
(cond ((and (empty? lst) (positive? i))
(error "index is too large for list"))
((zero? i)
(list (reverse acc) lst))
(else
(loop (rest lst) (cons (first lst) acc) (sub1 i)))))))
Also, we could implement our own versions of take
and drop
- again, this will traverse the input list twice:
(define (my-take lst i)
(if (> i 0)
(cons (first lst)
(my-take (rest lst) (- i 1)))
'()))
(define (my-drop lst i)
(if (> i 0)
(my-drop (rest lst) (- i 1))
lst))
(define (part lst i)
(list (my-take lst i)
(my-drop lst i)))
Upvotes: 6