Scheme: 3 numbers in a row, implementation [closed] - list

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Currently I have a list of elements (1 2 1 2 2 0 0 1 0).
The point of the function I'm trying to write is that it should display a possibility that would show 3 of the same number in a row (which would be a 'winning' case).
The output I would want is (1 2 1 2 2 2 0 1 0).
The function, when called, would be in the format of
(display (next 2 (list)))
I'd assume I'd take the car of the list and if there's a way to store/remember the car I got (in case I call for it again and want to check if it matches).

The closest thing to a basic loop is the named let construct. Here's a simple implementation that works for your problem:
(define (next e lst)
; l1 : part of the list already processed (reversed)
; l2 : part of the list still to be processed
; c-2: element before previous
; c-1: previous element
; res: result (list of winning cases
(let loop ((l1 null) (l2 lst) (c-2 null) (c-1 null) (res null))
(if (null? l2)
(reverse res)
(let ((ca (car l2)) (cd (cdr l2)))
(loop (cons ca l1) cd c-1 ca
(if (and (= ca 0) (= c-2 e) (= c-1 e))
(cons (append (reverse l1) (cons c-1 cd)) res) ; build winning case
res))))))
then
> (next 2 '(1 2 1 2 2 0 0 1 0))
'((1 2 1 2 2 2 0 1 0))
> (next 2 '(1 2 1 2 2 0 2 2 0))
'((1 2 1 2 2 2 2 2 0) (1 2 1 2 2 0 2 2 2))
> (next 1 '(1 2 1 2 2 0 1 1 0))
'((1 2 1 2 2 0 1 1 1))

Related

Is it possible to limit the number of calls to the cons function in the duplicate() function?

I wrote the function double() that duplicate the items in a list as follows:
(defun duplicate (l)
(if (null l) nil
(cons (car l) (cons (car l) ( duplicate (cdr l))))))
The duplicate() function make two calls to the CONS function for each item in a list:
Break 1 [2]> (trace cons)
;; Traçage de la fonction CONS.
(CONS)
Break 1 [2]> ( duplicate '(1 2 3))
1. Trace: (CONS '3 'NIL)
1. Trace: CONS ==> (3)
1. Trace: (CONS '3 '(3))
1. Trace: CONS ==> (3 3)
1. Trace: (CONS '2 '(3 3))
1. Trace: CONS ==> (2 3 3)
1. Trace: (CONS '2 '(2 3 3))
1. Trace: CONS ==> (2 2 3 3)
1. Trace: (CONS '1 '(2 2 3 3))
1. Trace: CONS ==> (1 2 2 3 3)
1. Trace: (CONS '1 '(1 2 2 3 3))
1. Trace: CONS ==> (1 1 2 2 3 3)
(1 1 2 2 3 3)
Is it possible to limit the number of calls to the CONS function to one per each list item?
NO, for the same reason you cannot fill a 10 liter bucket using 5 liters of water.
A list of 10 elements requires 10 cons cells.
A destructive version would make that possible:
(defun duplicate (l)
(if (null l)
nil
(destructuring-bind (f . r)
l
(setf (cdr l)
(cons f (duplicate r)))
l)))
CL-USER 10 > (duplicate (list 1 2 3 4 5))
(1 1 2 2 3 3 4 4 5 5)
You can eliminate all the cons calls:
(list* (car l) (car l) (duplicate (cdr l)))

Count specific numbers in list

How do I use count for counting specific numbers in list?
(define lst '(1 1 1 1 2 2 2 3 3 3 3 3 4 4)
(count 2 lst);; what should I use at the place of '2'
But it is resulting the following error.
count: contract violation
expected: procedure?
given: 2
count counts the number of elements of the list for which the procedure returns true. In this case you want a procedure that only returns true if the element is 2: (lambda (x) (equal? x 2)).
In full, you can do
(define lst '(1 1 1 1 2 2 2 3 3 3 3 3 4 4))
(count (lambda (x) (equal? x 2)) lst)
Side note: you can shorten it by replacing the lambda expression with (curry equal? 2).

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)

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.