Why is my Reverse Function Reversing All my Pairs BESIDES One? - scheme

i.e. I am given this (all possible combinations to make change for 11):
(list 1 1 1 1 1 1 1 5 5 5 5 1 1 1 10 10 10 1 1 25 25 25 25 25 25)
My code should return:
((7 . 1) (4 . 5) (3 . 1) (3 . 10) (2 . 1) (6 . 25))
so it is more readable.
However, it is returning:
((7 . 1) (4 . 5) (1 . 3) (3 . 10) (2 . 1) (6 . 25))
I don't know how to reverse the order of ALL my pairs.
This is my code:
(define (rev pair) ;; function reverses a pair, not a list.
(map (lambda (e) (cons (cdr e) (car e))) pair))
(define (rle coins)
(if (null? coins)
'()
(let loop ((firsts (list (car coins)))
(but-firsts (cdr coins)))
(if (or (null? but-firsts)
(not (equal? (car firsts) (car but-firsts))))
(rev (cons (cons (car firsts) (length firsts))
(rle but-firsts)))
(rev (loop (cons (car but-firsts) firsts) (cdr but-firsts)))))))
This is my test:
(rle (list 1 1 1 1 1 1 1 5 5 5 5 1 1 1 10 10 10 1 1 25 25 25 25 25 25))

Why not writing a classical tail-call recursive function?
Because my opinion is that named-loops are horrible constructs - unclear for the reader.
(define (rle coins (acc '()))
(if (null? coins)
(reverse acc)
(rle (cdr coins)
(if (and (not (null? acc)) (equal? (cdar acc) (car coins)))
(cons (cons (+ 1 (caar acc))
(cdar acc))
(cdr acc))
(cons (cons 1 (car coins))
acc)))))
It does correctly:
(rle (list 1 1 1 1 1 1 1 5 5 5 5 1 1 1 10 10 10 1 1 25 25 25 25 25 25))
;; '((7 . 1) (4 . 5) (3 . 1) (3 . 10) (2 . 1) (6 . 25))

First, some systematic testing (test cases should be systematic and as small as possible, not large and arbitrary):
> (rle '(2))
'((1 . 2))
> (rle '(2 3))
'((1 . 2) (3 . 1))
> (rle '(2 3 4))
'((1 . 2) (3 . 1) (1 . 4))
> (rle '(2 3 4 5))
'((1 . 2) (3 . 1) (1 . 4) (5 . 1))
> (rle '(2 3 4 5 6))
'((1 . 2) (3 . 1) (1 . 4) (5 . 1) (1 . 6))
When all the elements are unique, it looks like every other element is backwards.
> (rle '(5 5 6))
'((5 . 2) (1 . 6))
> (rle '(5 5 6 6))
'((5 . 2) (6 . 2))
> (rle '(5 5 6 6 6))
'((5 . 2) (3 . 6))
> (rle '(5 6 6 6))
'((1 . 5) (6 . 3))
When elements are repeated, the order seems a bit unpredictable.
Let's count how many times you rev each element by using triple elements with the counter as the car:
;; Flip the order of a pair.
(define (flip x)
(cons (cdr x) (car x)))
;; Add one to the car of each element and flip its cdr.
(define (rev list)
(map (lambda (x) (cons (+ 1 (car x)) (flip (cdr x)))) list))
(define (rle coins)
(if (null? coins)
'()
(let loop ((firsts (list (car coins)))
(but-firsts (cdr coins)))
(if (or (null? but-firsts)
(not (equal? (car firsts) (car but-firsts))))
(rev (cons (cons 0 (cons (car firsts) (length firsts)))
(rle but-firsts)))
(rev (loop (cons (car but-firsts) firsts) (cdr but-firsts)))))))
This creates a list that says how many times rev has been applied to each element in the result.
> (rle '(99))
'((1 1 . 99))
> (rle '(99 99))
'((2 99 . 2))
> (rle '(99 99 99))
'((3 3 . 99))
> (rle '(99 99 99 100))
'((3 3 . 99) (4 100 . 1))
> (rle '(99 99 99 100 100))
'((3 3 . 99) (5 2 . 100))
As you can see, each element has been "flipped" many times - once for every time you recurse.
This happens because you apply rev to every partial result, and not just on the final list.
The elements that have been flipped an even number of times are "backwards".
Now, your example input:
> (rle (list 1 1 1 1 1 1 1 5 5 5 5 1 1 1 10 10 10 1 1 25 25 25 25 25 25))
'((7 7 . 1) (11 4 . 5) (14 1 . 3) (17 3 . 10) (19 2 . 1) (25 6 . 25))
where we can see that the third element has been flipped an even number of times, and this is what's causing it to be backwards.
The best solution is to build your pairs in the order you want them, so you don't need to adjust them afterwards; the implementation is left as an exercise.
(The implementation is a very minor change in your procedure, and the removal of rev.)

Related

Why the same data is printed differently when built with list or cons? [duplicate]

This question already has answers here:
Dot notation in scheme
(3 answers)
Closed 5 years ago.
I tried to reproduce the same data layout by using different combinations of list and cons. In MIT Scheme, the same data layout seems to be printed differently depending on how it was built.
In example,
> (cons 1 (cons 2 3))
(1 2 . 3)
> (list 1 (cons 2 3))
(1 (2 . 3))
> (cons 1 (list 2 3))
(1 2 3)
> (list 1 (list 2 3))
(1 (2 3))
The underlying data should always be the same. Why does MIT Scheme represents it differently? Is the underlying arrangements of pairs really the same every time?
Each of the inputs is building a different output, so they're printed differently. Notice that the following expressions are equivalent:
(cons 1 (cons 2 3))
; (1 2 . 3)
(list 1 (cons 2 3))
(cons 1 (cons (cons 2 3) '()))
; (1 (2 . 3))
(cons 1 (list 2 3))
(cons 1 (cons 2 (cons 3 '())))
; (1 2 3)
(list 1 (list 2 3))
(cons 1 (cons (cons 2 (cons 3 '())) '()))
; (1 (2 3))
Remember: a list is defined if and only if the cdr part of each cons is also a cons cell, or an empty list.

How do foldl and foldr work, broken down in an example?

Okay, I am new with scheme/racket/lisp. I am practicing creating my own functions, syntax, and recursion, so I want to make my own foldl and foldr functions that do exactly what the predefined versions do. I can't do it because I just don't understand how these functions work. I have seen similar questions on here but I still don't get it. Some examples broken down would help! Here is my (incorrect) process:
(foldl - 0 '(1 2 3 4)) I do 0 -(4-3-2-1) and get 2 which is the right answer
(foldl - 0 '(4 3 2 1)) I do 0-(1-2-3-4) and get 8 but it should be -2.
(foldr - 0 '(1 2 3 4)) I do 0-(1-2-3-4) and get 8 again, but it should be -2.
(foldr - 0 '(4 3 2 1)) I do 0-(4-3-2-1) and get 2 which is the right answer.
What am I doing wrong?
Let's look at: (foldr - 0 '(1 2 3 4)).
Here the literal '(1 2 3 4) constructs a list whose elements are the numbers 1, 2, 3, and, 4. Let's make the construction of the list explicit:
(cons 1 (cons 2 (cons 3 (cons 4 empty))))
One can think of foldr as a function that replaces cons with a function f and empty with a value v.
Therefore
(foldr f 0 (cons 1 (cons 2 (cons 3 (cons 4 empty)))))
becomes
(f 1 (f 2 (f 3 (f 4 v)))))
If the function f is - and the value v is 0, you will get:
(- 1 (- 2 (- 3 (- 4 0)))))
And we can calculate the result:
(- 1 (- 2 (- 3 (- 4 0))))
= (- 1 (- 2 (- 3 4)))
= (- 1 (- 2 -1))
= (- 1 3)
= -2
Note that (foldr cons empty a-list) produces a copy of a-list.
The function foldl on the other hand uses the values from the other side:
> (foldl cons empty '(1 2 3 4))
'(4 3 2 1)
In other words:
(foldl f v '(1 2 3 4))
becomes
(f 4 (f 3 (f 2 (f 1 v)))).
If f is the function - and the value is 0, then we get:
(- 4 (- 3 (- 2 (- 1 0))))
= (- 4 (- 3 (- 2 1)))
= (- 4 (- 3 1))
= (- 4 2)
= 2
Note that (foldl cons empty a-list) produces the reverse of a-list.
You can illustrate what is going on in fold, if you create a procedure, which does the same like cons but reverses the arguments. I have called it snoc in the following example.
(define fldl
(lambda (proc a lst)
(if (pair? lst)
(fldl proc
(proc (car lst)
a)
(cdr lst))
a)))
(define fldr
(lambda (proc a lst)
(if (pair? lst)
(proc (car lst)
(fldr proc
a
(cdr lst)))
a)))
(define lst (list 1 2 3 4))
(fldl + 0 lst) ;; => 10
(fldl * 1 lst) ;; => 24
(fldl cons '() lst) ;; => (4 3 2 1)
(fldr + 0 lst) ;; => 10
(fldr * 1 lst) ;; => 24
(fldr cons '() lst) ;; => (1 2 3 4)
(define snoc (lambda (a b) (cons b a)))
(fldl snoc '() lst) ;; => ((((() . 1) . 2) . 3) . 4)
(fldr snoc '() lst) ;; => ((((() . 4) . 3) . 2) . 1)

Can someone explain the difference between Cons and Append in scheme?

I read both of them and they seem to both construct a single list, what's their difference?
cons is the constructor for all pairs.
A proper list is () (the empty list, aka nil) or a pair where the cdr is a proper list. Any chain of pairs where the last one has () as it's cdr is a proper list (in addition to the empty list itself).
A dotted list is a pair that does not have a proper list as it's cdr. Thus a chain of pairs where the last cdr is not () matches this.
;; dotted lists
(cons 1 2) ; ==> (1 . 2)
(cons 1 (cons 2 3)) ; ==> (1 2 . 3) or (1 . (2 . 3))
;; proper lists
(cons 1 '()) ; ==> (1) or (1 . ())
(cons 1 (cons 2 '())) ; ==> (1 2) or (1 . (2 . ()))
append is a procedure that uses cons to make a list with all the elements of the argument lists left to right. A common implementation of append for just two lists would be:
(define (append lst tail)
(if (null? lst)
tail
(cons (car lst)
(append (cdr lst)
tail))))
append will fail if one of the arguments except the last is not a proper list. Tail and can be any value:
(append '(1 2 3) '(4 5)) ; ==> (1 2 3 4 5) or (1 . (2 . (3 . (4 . (5 . ())))))
(append '(1 2 3) '(4 5 . 6)) ; ==> (1 2 3 4 5 . 6) or (1 . (2 . (3 . (4 . (5 . 6)))))
(append '(1 2 3) #f) ; ==> (1 2 3 . #f) or (1 . (2 . (3 . #f)))
(append '(1 2 . 3) '(4 5 . 6)) ; ==> error `car` of number not allowed

How to Merge 2 lists into one in racket

I have 2 dynamic lists that I would like to merge into one.
Say
'(1 2 3 4)
and
'(15 16)
and get
'(1 2 3 4 15 16)
How can this be done?
Use append for this:
(append '(1 2 3 4) '(15 16))
=> '(1 2 3 4 15 16)
Or, if you're merging two sorted lists and need to maintain the ordering in the result list:
(require srfi/1)
(define (merge-sorted-lists lhs rhs #:order (lt? <))
(let loop ((result '())
(lhs lhs)
(rhs rhs))
(cond ((null? lhs) (append-reverse result rhs))
((null? rhs) (append-reverse result lhs))
((lt? (car rhs) (car lhs))
(loop (cons (car rhs) result) lhs (cdr rhs)))
(else
(loop (cons (car lhs) result) (cdr lhs) rhs)))))
Examples:
> (merge-sorted-lists '(1 3 5 7) '(2 4 6 8))
'(1 2 3 4 5 6 7 8)
> (merge-sorted-lists '(7 5 3 1) '(8 6 4 2) #:order >)
'(8 7 6 5 4 3 2 1)

How to count and remove element at the same time in the list in Scheme

I have two procedures, one for counting an element in the list and the other one for removing the same element from the same list. What should I do for counting and removing at the same time? I am trying it for long time but nothing is working. I work with this list: (list 1 2 3 2 1 2 3), finally it should be like: ((1 . 2) (2 . 3) (3 . 2)). The first number of pair is an element and second number of pair is sum of first pair's number from all list.
My try:
1) it works only with counting and result is: ((1 . 2) (2 . 3) (3 . 2) (2 . 2) (1 . 1) (2 . 1) (3 . 1))
2) it works only with removing and result is: ((1 . 2) 2 3 2 2 3)
Where is the problem?
This is for counting:
(define count-occurrences
(lambda (x ls)
(cond
[(memq x ls) =>
(lambda (ls)
(+ (count-occurrences x (cdr ls)) 1))]
[else 0])))
(count-occurrences '2 (list 1 2 3 2 1 2 3)) -> 3
This is for removing:
(define (remove-el p s)
(cond ((null? s) '())
((equal? p (car s)) (remove-el p (cdr s)))
(else (cons (car s) (remove-el p (cdr s))))))
(remove-el '2 (list 1 2 3 2 1 2 3)) -> (1 3 1 3)
Just return the count and the removed list at once. I call this routine
count-remove. (Pardon to all schemers for not idiomatic or efficient style)
(define (count-remove ls x)
(letrec ([loop (lambda (count l removed)
(cond
[(eq? l '()) (list count removed)]
[(eq? (car l) x) (loop (+ 1 count) (cdr l) removed)]
[else (loop count (cdr l) (cons (car l) removed))]))])
(loop 0 ls '())))
(define (count-map ls)
(cond
[(eq? ls '()) '()]
[else
(letrec ([elem (car ls)]
[cr (count-remove ls elem)])
(cons (cons elem (car cr)) (count-map (cadr cr))))]))
Here is some usage:
(count-map '(1 1 2 3 2))
((1 . 2) (2 . 2) (3 . 1))

Resources