Scheme remove a list - 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.

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

How concatenate sublist in scheme?

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)

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)

opposite of list-ref? (Racket)

Is there anything which acts as the opposite of list-ref, where instead of selecting certain values to add to a list, it'll take values away from a list?
I basically want to do the following
(list 1 2 3 4 5 6 7) (list 3 6 7) -> (list 1 2 4 5)
Where the values in list two get deleted from list one. (preferred)
Since I will always start with a list that goes from 1 to n,
the second list could also represent the location/position where a number on list 1 should be deleted. (less preferred)
I'm trying to create a code which will manipulate other functions to come up with these lists, so please be clear where each list is 'mentioned' in the code, as I sometimes get confused if people use x y and z and so forth with multiple lambda, local definitions, etc.
I have something here which does the opposite of what I want and I've been trying to alter it so instead of outputting the elements of x that are on y, it gives the elements of x which are NOT on y.
(define (selection x y)
(filter (lambda (e2)
(ormap (lambda (e1) (equal? e1 e2))
y))
x))
example:
(list 1 2 3 4 5 6 7 8 9 10)
(list 2 4 6 8 10))
-> (list 2 4 6 8 10))
Anybody have any ideas on how to change the output to what I need?
It sounds like you're using lists as sets. You could instead use Racket sets, and use the set-subtract function:
#lang racket
(set-subtract (set 1 2 3 4 5 6 7)
(set 3 6 7))
;; => (set 1 2 4 5)
remove will do the trick I guess.
> (remove* (list 1 2) (list 1 2 3 2 4 5 2))
'(3 4 5)
You can read the doc here.
Here's a simple recursive function that achieves what you want:
(define remove-list-from-list (lambda (list remlist)
(cond
[(null? list) '()]
[(member (car list) remlist) (remove-list-from-list (cdr list) remlist)]
[else (cons (car list) (remove-list-from-list (cdr list) remlist))])))
Now you can use it like so:
> (remove-list-from-list (list 1 2 3 4 5 6 7) (list 3 6 7))
'(1 2 4 5)

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