How concatenate sublist in scheme? - list

For example the list '((1 2 3) (2 3 4) (4 5 6))
result (1 2 3 2 3 4 4 5 6)
(
define (concatenate list1 list2)
(if (null? list1)
list2
(
(concatenate (cdr list1) (append (car list1) '()) )
)
)
)
My idea is list1 = '((1 2 3) (2 3 4) (4 5 6)) and the result is list2 = (1 2 3 2 3 4 4 5 6)

We only need one list parameter, given that it's already a list of lists, and there's no use for a second parameter to be used as an accumulator. Try this:
(define (concatenate lsts)
(apply append lsts))
(concatenate '((1 2 3) (2 3 4) (4 5 6)))
=> '(1 2 3 2 3 4 4 5 6)

Related

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

Scheme: Mapping a list as argument to a function

If I have a function that takes 3 arguments, and returns a list:
(some-function 1 2 3) --> '(3 2 1)
and I have a list of lists like this:
( (1 2 3) (2 1 3) (3 2 1) )
How can I map "some-function" to use all the lists as elements?
Thank you.
If the lists are only nested once then it is possible to turn them into a single list using fold and append and call some-function on the result with apply i.e
(fold append '() '((1 2 3) (2 1 3) (3 2 1))) => (2 3 1 3 2 1 1 2 3)
(apply some-function (2 3 1 3 2 1 1 2 3))
Otherwise you can just wrap apply and the some-function in a lambda you pass to map
(map (lambda (x) (apply some-function x)) '((1 2 3) (2 1 3) (3 2 1)))
I am not sure what result you mean.
(define (rev-list a b c)
(list c b a))
(rev-list 1 2 3)
⇒ (3 2 1)
(apply rev-list '((1 2 3) (2 1 3) (3 2 1)))
⇒ ((3 2 1) (2 1 3) (1 2 3))
(map (lambda (l) (apply rev-list l)) '((1 2 3) (2 1 3) (3 2 1)))
⇒ ((3 2 1) (3 1 2) (1 2 3))

Recursive functions that rotate n elements of a list to left and right in lisp

The function has 1 parameter, an integer.
For example rot-left(2 '(1 2 3 4 5)) should return (3 4 5 1 2 ) and rot-right(2 '(1 2 3 4 5)) should return (5 4 1 2 3).
I've tried this... it doesn't work but what it's supposed to do is add the last n elements of a list to an empty list.
(defun rot_left (n l)
(if (zerop n)
'()
(append (last l)
rot-left ((- n 1) (cdr l)))))
I will give a solution assuming that, if the function rot-right should rotate the elements of the list from right to left, (rot-right 2 '(1 2 3 4 5)) should produce (4 5 1 2 3) and not (5 4 1 2 3).
Then, assuming that this interpretation is correct, the functions can be written only by means of primitive operators in Common Lisp, without the use of iteration or recursion:
(defun rot-left(n l)
(append (nthcdr n l) (butlast l (- (length l) n))))
(defun rot-right(n l)
(rot-left (- (length l) n) l))
(defvar a '(1 2 3 4 5))
(rot-left 2 a) ; produces (3 4 5 1 2)
(rot-right 2 a) ; produces (4 5 1 2 3)

Replacing an element into a list Scheme

I need to replace an element from a list with another element in Scheme, but the problem is that the list where I need to replace can be nested.
For example, if I have the list '(1 (2 3 4 5) (6 7)) and I need to replace 5 with 9, my output should be '(1 (2 3 4 9) (6 7)).
Can you please help me with this problem?
There is a basic strategy for solving this kind of problem:
First, solve it for a flat list. i.e., write the function so that it works if the input list has no sublists.
Then, add a condition so that if the element you're inspecting is a list, then recurse into your function with that list.
Here's some skeletal code:
(define (replace lst from to)
(cond ((null? lst) '()) ;; end of input
((list? (car lst)) <???>) ;; encountered a sublist
((equal? (car lst) from) <???>) ;; found the element we're replacing
(else <???>))) ;; everything else
Notice that the second cond clause, (list? (car lst)), is the only thing that's new in your sublist-capable version.
here is a function:
(define (replace L new old)
(cond ;;((null? L) L)
((list? L)
(map
(lambda (lst) (replace lst new old))
L))
(else
(if (equal? L old)
new
L))))
examples of use:
> (replace '(1 (1 2 3 4 (5 6 3) 3 4)) 7 3)
'(1 (1 2 7 4 (5 6 7) 7 4))
> (replace '() 7 3)
'()
> (replace '(1 (1 2 3 4) 3 4) 7 3)
'(1 (1 2 7 4) 7 4)
or:
(define (replace L new old)
(if (list? L)
(map
(lambda (lst) (replace lst new old))
L)
(if (equal? L old)
new
L)))
example:
(replace '(1 (1 2 3 4 (5 6 3) 3 4)) 7 3) -> '(1 (1 2 7 4 (5 6 7) 7 4))

Scheme remove a list

I found the contents of this thread quite useful!
How to delete an element from a list in scheme
I tested the code recommended, and it seems that it removes a single item at its first and only occurrence in the list.
Say instead I wanted to all occurrences of the item from the list. Or even further, if I wanted to specify a list of items instead of an item to remove.
For example if I had a function called removelist that took two lists as parameters
(define (removelist L M))
> (removelist '(1 2 2 3 4 5 2 2 5 6 7 8 9) '(1 2))
> '(3 4 5 5 6 7 8 9)
Hope this makes sense.
Here a simple function that uses filter and member to accomplish this:
(define (remove-list l m)
(filter (lambda (element)
(not (member element m)))
l))
Here the results:
> (remove-list '(1 2 2 3 4 5 2 2 5 6 7 8 9) '(1 2))
(3 4 5 5 6 7 8 9)
> (remove-list '(1 2 2 3 4 5 2 2 5 6 7 8 9) '(1 2 1))
(3 4 5 5 6 7 8 9)
This snippet requires srfi-1. Hope this helps.
Regards,
Matt
Using simple recursion and no built-in functions like filter or member:
(define (filter_out m l)
(cond ( (null? l) '() )
( (equal? (car l) m) (filter_out m (cdr l)) )
( else (cons (car l) (filter_out m (cdr l))) )
))
Test:
(filter_out 'jay (list 'jay 'z 'jay 'dilla 'jay 'electro))
(filter_out '(jay z) (list '(jay z) '(jay dilla) 'jay '(electro)))
If you're interested in learning this type of coding, check out "The Little Schemer." It takes only a few hours to read and you'll be a master at recursion after reading it.