Subtraction of a list of numbers in racket - list

I'm trying to subract a list of numbers using recurssion in racket. The function goes like:
(define (sub lst)
(cond [(empty? lst) 0]
[ else (- (first lst) (sub (rest lst)))]))
This doesn't seem to be correct as racket performs subtraction from left to right. I.e eg:
(- 1 2 3 4 6) is suppose to be -14. But when i do it in the same way as giving in the list through recurssion, like (list 1 2 3 4 6) it gives the result as 4. How can i solve this?

So your function does this:
(sub '(1 2 3)) ; ==
(- 1 (- 2 (- 3 0))) ; ==
(- 1 (- 2 3)) ; ==
(- 1 -1) ; ==
; ==> 2
What you function needs to do is this:
(- (- 1 2) 3) ; ==> -4
There is also special cases for 0 and 1 argument:
(sub '()) ; ==> 0 (identity of - is 0)
(sub '(1)) ; ==> -1 (- identity 1)

Related

Duplicate n times an element from a list in Racket

for example:
(duplicate 3 (list 1 2 3)) = (list 1 1 1 2 2 2 3 3 3)
i tried this:
(define (duplicate n l)
(cond [(zero? n) empty]
[else (cons l (duplicate (sub1 n) l))]))
but it gives me:
(duplicate 2 (list 1 2)) = (list (list 1 2) (list 1 2))
You are actually half way. What you have created is something that takes one element and a count and makes a list of that many elements.
(duplicate 3 'e) ; ==> (3 3 3)
That means that you can use that:
(duplicate-list 3 l)
; ==> (append (duplicate 3 (car l))
; (duplicate-list 3 (cdr l)))
(define (duplicate n x)
"Repeat x n times."
(cond [(zero? n) empty]
[else (cons x (duplicate (sub1 n) x))]))
(define (mappend fn . lists)
"map but appending the results."
(apply append (apply map fn lists)))
(define (duplicate-list n l)
"duplicate each element in l."
(mappend (lambda (x) (duplicate n x)) l))
Then
(duplicate-list 3 (list 1 2 3))
;; '(1 1 1 2 2 2 3 3 3)

How to transform list into sub lists?

((1 2 3)
(2 3 4)
(3 4 5)
(4 5 6))
from
(1 2 3 4 5 6)
And what is the type of such operation?
What I tried:
(loop
:with l2 = '()
:with l1 = '(1 2 3 4 5 6)
:for i :in l1
:do (push (subseq l1 0 3) l2))
You're pushing the same sublist every time through the loop.
You can use :for sublist on to loop over successive tails of a list.
And use :collect to make a list of all the results, rather than pushing onto your own list
(loop
:for l1 on '(1 2 3 4 5 6)
:if (>= (length l1) 3)
:collect (subseq l1 0 3)
:else
:do (loop-finish))
Alternatively use map:
(let ((l '(1 2 3 4 5 6)))
(map 'list #'list l (cdr l) (cddr l)))
;; ((1 2 3) (2 3 4) (3 4 5) (4 5 6))
You can read it as:
for list l with values (1 2 3 4 5 6)
map over the list and its two successive cdrs
by applying #'list on the elements of the lists map is looping through in parallel
(stopping when shortest list is used up)
and collecting the results as/into a 'list
#WillNess suggested even simpler:
(let ((l '(1 2 3 4 5 6)))
(mapcar #'list l (cdr l) (cddr l)))
thanks! So then we could generalize using only map variants:
(defun subseqs-of-n (l n)
(apply #'mapcar #'list (subseq (maplist #'identity l) 0 n)))
(maplist #'identity l) is equivalent to (loop for sl on l collect sl).
However,
(loop for sl on l
for i from 0 to n
collect sl)
is better because it stops at n-th round of looping ...
First let's define a function take-n, which either returns n items or an empty list, if there are not enough items. It will not scan the whole list.
(defun take-n (n list)
(loop repeat n
when (null list) return (values nil nil)
collect (pop list)))
Then we move this function take-n over the list until it returns NIL.
(defun moving-slice (n list)
(loop for l on list
for p = (take-n n l)
while p
collect p))
Example:
CL-USER 207 > (moving-slice 3 '(1 2))
NIL
CL-USER 208 > (moving-slice 3 '(1 2 3))
((1 2 3))
CL-USER 209 > (moving-slice 3 '(1 2 3 4 5 6 7))
((1 2 3) (2 3 4) (3 4 5) (4 5 6) (5 6 7))
Here's a version of Barmar's answer (which should be the accepted one) which is a bit more general and only calls length once.
(defun successive-leading-parts (l n)
(loop repeat (1+ (- (length l) n))
for lt on l
collect (subseq lt 0 n)))
> (successive-leading-parts '(1 2 3 4) 3)
((1 2 3) (2 3 4))
> (successive-leading-parts '(1 2 3 4) 2)
((1 2) (2 3) (3 4))
Or the classical more C-like for-loop-ing with indexes to solve it.
But use it more on strings/vectors but less on lists, because its performance is
for lists quadratic
for vectors (strings!) linear, so preferably to be used with them!
credits and thanks to #WillNess who pointed both points out (see comments below).
(defun subseqs-of-n (ls n) ;; works on strings, too!
(loop :for i :from 0 :to (- (length ls) n)
:collect (subseq ls i (+ i n))))
So on vectors/strings use:
(subseqs-of-n "gattaca" 5)
;; ("gatta" "attac" "ttaca")

Adding a single element onto a list until a certain point

I want to make a function that given a list and a natural number, adds zeros onto the list so the length of the list equals the natural number. What is an efficient way of doing this so instead of making every element zero, it does what it's supposed to do
(define (zero-list loz alon)
(cond
[(empty? loz) empty]
[(= (-(length loz) 1) alon) (cons 0 loz)]
[else (cons 0 (zero-list (rest loz)))]))
Example:
(zero-list (list 1 2 3) 5)) -> (list 0 0) so (length (list 1 2 3)) + (length (list 0 0)) = 5
Use make-list to generate a list that has the appropriate number of 0s (i.e. difference between the number and the length of the input list):
(define (zero-list l n)
(make-list (- n (length l)) 0))
(zero-list (list 1 2 3) 5) ; -> (list 0 0)

How to move first list item to the end?

For given list:
(1 2 3 4)
I'd like to get as output:
(2 3 4 1)
Code I came up with looks like this:
(flatten (cons (rest l) (list (first l))))
However my feeling is, that I overcomplicated this. Any other ideas?
You don't need to flatten a cons, just use concat.
Here is an example:
(let [fruit ["apple" "orange" "grapes" "bananas"]]
(concat (rest fruit) [(first fruit)])
Developing #stonemetal's hint, we can quickly and lazily rotate a vector thus:
(defn rotate [v n]
(let [cv (count v), n (mod n cv)]
(concat (subvec v n cv) (subvec v 0 n))))
It works in either direction:
(map #(rotate (vec (range 5)) %) (range -2 8))
;((3 4 0 1 2)
; (4 0 1 2 3)
; (0 1 2 3 4)
; (1 2 3 4 0)
; (2 3 4 0 1)
; (3 4 0 1 2)
; ...
; (2 3 4 0 1))
So to rotate the first in a sequence to the end:
(rotate (vec (range 1 5)) 1)
You can also use destructuring (either on the function arguments or in a let binding).
(let [[h & tail] '(1 2 3 4)]
(concat tail (list h))) ;=> (1 2 3 4)

Build-list within build-list Scheme/DrRacket

Trying to make a list that has n elements with each of those lists having r elements. i.e.
(function 2 3) would be (list (list 0 0 0)(list 0 1 2)). And those elements are made by multiplying the nth element by the rth element starting at 0. This is my code:
(define (nr nc)
(build-list nr (lambda (x)
(build-list nc (lambda (x) (* x 1))))))
so I have (function 2 3) coming out to (list (list 0 1 2)(list 0 1 2)) and I can't figure out how to multiply the first list by 0, the second by 1, third by 2, and so on.
You were close:
(define (build nr nc)
(build-list nr (lambda (r)
(build-list nc (lambda (c) (* r c))))))
> (build 2 3)
'((0 0 0) (0 1 2))
> (build 3 3)
'((0 0 0) (0 1 2) (0 2 4))
An alternative:
(define (build2 nr nc)
(for/list ([r nr])
(for/list ([c nc])
(* r c))))
(define (range n)
(define (range-iter i accum)
(if (= i 0) (cons 0 accum)
(range-iter (- i 1) (cons i accum))))
(range-iter (- n 1) `()))
(define (nested-list n r)
(map
(lambda (multiplier)
(map
(lambda (cell) (* cell multiplier))
(range r)))
(range n)))