opposite of list-ref? (Racket) - list

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)

Related

Advice on how to tackle this lisp function.

I have written a function called my_rotate that takes a number from a user and creates a list up to five numbers. my_rotate then, pops off the first element of the list and adds it to the end of the list. Any advice on how I could write my_rotate to take in another number n and rotate the list based on the number n, in which the user entered.
Example:
> (my_rotate 1 2)
Outputs:
(3 4 5 1 2)
This is what I have so far:
(defun my_rotate (y)
(append (loop for i from (+ 1 y) to (+ 4 y) collect i)
(list y)))
Here the function.
I create two lists and then concatenate them.
(defun my-rotate (length shift)
"Return a list of given LENGTH, rotated by SHIFT."
(nconc
(loop for i from (1+ shift) to (- length shift -2) collect i)
(loop for i from 1 to shift collect i)))
(my-rotate 7 2)
==> (3 4 5 6 7 1 2)
Note that since both loops produce fresh lists, I use nconc instead of append.
If, however, you want to rotate an existing list, you will need to do something else:
(defun rotate-list (list shift)
"Rotate the given LIST by the specified SHIFT."
(let ((len (length list)))
(setq shift (mod shift len)) ; handle circular shifts
(append (nthcdr (- len shift) list)
(butlast list shift))))
(rotate-list '(1 2 3 4 5 6) 2)
==> (5 6 1 2 3 4)
(rotate-list '(1 2 3 4 5 6) 20)
==> (5 6 1 2 3 4) ; same because 20 = 2 mod 6
(rotate-list '(1 2 3 4 5 6) 0)
==> (1 2 3 4 5 6) ; unchanged
Note that nthcdr points inside the original list, so we have to use append to avoid modifying the argument.
Note also that we scan the list argument twice (once in nthcdr and once in butlast).
If your lists are huge, and profiling shows that this function is the bottleneck, you might want to re-write this using a loop (this is scenario is so unlikely, that I already regret having wasted my time writing this note).

Extend a Scheme list using the same list values

I need to create a Scheme function that receives a list and a desired new size, the function then extends the list size by using the same list values. For example:
'(1 2 3) to size 6 will turn to '(1 2 3 1 2 3)
'(1 2) to size 5 will turn to '(1 2 1 2 1)
'(4 5 6 1) to size 7 will turn to '(4 5 6 1 4 5 6)
The new length function parameter can be equal or bigger than the current list size.
You can use SRFI 1 function circular-list (alongside Racket's built-in take) to do this:
(require srfi/1)
(define (take-circular lst n)
(take (apply circular-list lst) n))
If you want to avoid using SRFI 1, another method works like this:
(define (take-circular lst n)
(let ((size (length lst)))
(if (> n size)
(append lst (take-circular lst (- n size)))
(take lst n))))

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.

Scheme: change value of an element in a list

I hate using SO as a way to find simple functions, but I really can't find a function like this anywhere:
Given a list (1 2 3 4 5), I'd like the equivalent of (PHP's, Perl's, Python's)
$a = array(1, 2, 3, 4, 5);
$a[3] = 100;
Which results in (1 2 3 100 5)
Thanks!
You can write list-set! of Guile, like so:
(define a (list 1 2 3 4)) ; a is '(1 2 3 4)
(define (list-set! list k val)
(if (zero? k)
(set-car! list val)
(list-set! (cdr list) (- k 1) val)))
(list-set! a 2 100) ; a is '(1 2 100 4)
(Tried this in DrRacket.)
Using standard functions without any SRFI:
(set-car! (list-tail lst k) val)
I may be a bit late, but I have a different answer.
Part of the functional-program paradigm seems to be to try to avoid modifying data when possible. For efficiency reasons you may want to go with the other answers here. But otherwise, consider a non-mutating function such as this:
(define (list-with lst idx val)
(if (null? lst)
lst
(cons
(if (zero? idx)
val
(car lst))
(list-with (cdr lst) (- idx 1) val))))
Which passes the following tests:
(describe "a function that returns a list with a 'changed' value"
(it "can modify the edges of lists without having 1-off errors"
(expect (list-with '(1 2 3 4 5) 0 99) (be equal? '(99 2 3 4 5)))
(expect (list-with '(1 2 3 4 5) 4 99) (be equal? '(1 2 3 4 99))))
(it "has something to do with creating new lists"
(expect (list-with '(1 2 3 4 5) 2 99) (be equal? '(1 2 99 4 5))))
(it "doesnt just modify the contents of the original list"
(let ((a '(1 2 3 4 5)))
(list-with a 2 99)
(expect a (be equal? '(1 2 3 4 5))))))
(The code is written in Chicken Scheme and the tests with the "missbehave" library. But it seems like pretty portable Scheme.)
Guile has a built-in function called list-set! that does exactly what you want, using zero-based indices. For your example, you would have:
(define a '(1 2 3 4 5))
(list-set! a 3 100)
I don't think this is standard Scheme, however, and I don't know if it's really efficient. For a fixed-length array you should probably use a vector:
(define a2 #(1 2 3 4 5))
(vector-set! a2 3 100)
I'm pretty sure this is part of the language standard.

Scheme How to Take the first item in the List?

Say I want to take the first item of the lists '(4 3 1) '(5 6 8)
I want something like this
(first '(4 3 1) '(5 6 8))
should return me the first item
(4 3 1)
as result. Is there something like this in scheme build-in function I can call ?
car doesn't work, as it only returns me the first item inside 1 list
list-ref doesn't work, same reason above, returns me 1 item inside the list
How can I do that? if I need to write it myself this first function ?
You can use the list-ref procedure to get an element from a list, using its index, for example:
(let ((l '((4 3 1) (5 6 8))))
(list-ref l 0)) ; get the element at index 0
However if you only want the first element, you can use car:
(let ((l '((4 3 1) (5 6 8))))
(car l))
Check the snippet running here.
You can use "." in function definition to take arbitrary number of arguments.
(define (first . args) (car args))
(first '(4 3 1) '(5 6 8)) ;; => (4 3 1)
You're trying too hard:
> (define (first a b) a)
> (first '(1 2 3) '(4 5 6))
(1 2 3)
It's been a while since I used scheme, but wouldn't you need to have the lists in their own list first
(first (list '(4 3 1) '(5 6 8)))