Modify part of list using set? - scheme

Using set! I want to be able to modify a local state list variable lst, but only a part of it
For example, I want to insert values inside an inner list:
((1 2) (4 5))
becomes
((1 2 3) (4 5))
I want to be able to do something like set! (car lst) (append (car lst) 3)
But that seems to only modify the temporary variable generated by (car lst).
The only way I can think of is to create a new list with the new desired values and set lst to be the new list, but that seems wasteful and unnecessary. Is there a better way to do it?

try this:
(define lst (list (list 1 2) (list 4 5)))
lst
> ((1 2) (4 5))
(set-cdr! (cdar lst) (list 3))
lst
> ((1 2 3) (4 5))
when modifying cons/lists you should use set-cdr! and set-car!
EDIT: for racket
use mutable list:
(require racket/mpair)
(define lst (mlist (mlist 1 2) (mlist 4 5)))
lst
> (mcons (mcons 1 (mcons 2 '())) (mcons (mcons 4 (mcons 5 '())) '()))
(set-mcdr! (mcdr (mcar lst)) (list 3))
> (mcons (mcons 1 (mcons 2 #<promise:temp2>)) (mcons (mcons 4 (mcons 5 '())) '()))
lst

Depending on which interpreter of Scheme you're using, you might need to do a bit more of work. For instance, in Racket the list primitives are not mutable by default, and you'll have to use the mutable version of the procedures:
(require scheme/mpair)
(define lst (mlist (mlist 1 2) (mlist 4 5)))
lst
(set-mcdr! (mcdr (mcar lst)) (mlist 3))
lst

The standard idiom in Scheme for creating a list piecemeal is to prepend elements to the front, using cons, and not trying to set-cdr! the last cons cell in the list. At the end, when your list is done, you can then use reverse to get the elements in the correct order. This way, no list mutation is necessary per se.
So if you're trying to create the list (1 2 3) piecemeal:
Start off with the empty list, (), and cons 1 to it. This gives you (1).
Then cons 2 to the list: (2 1)
Then cons 3 to the list: (3 2 1)
Finally, when you're done building the list, reverse it: (1 2 3)
You may ask why this is "better". That's because accessing the last pair to set-cdr! is an O(n) operation; with linked lists, elements are not random-access, but are linear on the element position being accessed. Whereas, cons is always O(1).
reverse is an O(n) operation, but as long as you're doing it only at the end (when you are ready to build the list in the correct order), rather than calling it all the time, that won't detrimentally affect performance.

Related

Pair combinations in scheme

I'm trying to find the various combinations that can be made with a list of N pairs in scheme. Here is where I'm at thus far:
(define (pair-combinations list-of-pairs)
(if (null? list-of-pairs)
nil
(let ((first (caar list-of-pairs))
(second (cadar list-of-pairs))
(rest (pair-combinations (cdr list-of-pairs))))
(append
(list (cons first rest))
(list (cons second rest))
))))
Now, I'm not sure if the logic is correct, but what I notice immediately is the telescoping of parentheticals. For example:
(define p1 '( (1 2) (3 4) (5 6) ))
(pair-combinations p1)
((1 (3 (5) (6)) (4 (5) (6))) (2 (3 (5) (6)) (4 (5) (6))))
Obviously this is from the repetition of the list (... within the append calls, so the result looks something like (list 1 (list 2 (list 3 .... Is there a way to do something like the above in a single function? If so, where am I going wrong, and how would it be properly done?
The answer that I'm looking to get would be:
((1 3 5) (1 3 6) (1 4 5) (1 4 6) (2 3 5) (2 3 6) (2 4 5) (2 4 6))
That is, the possible ways to choose one element from N pairs.
Here is one way to think about this problem. If the input is the empty list, then the result is (). If the input is a list containing a single list, then the result is just the result of mapping list over that list, i.e., (combinations '((1 2 3))) --> ((1) (2) (3)).
Otherwise the result can be formed by taking the first list in the input, and prepending each item from that list to all of the combinations found for the rest of the lists in the input. That is, (combinations '((1 2) (3 4))) can be found by prepending each element of (1 2) to each of the combinations in (combinations '((3 4))), which are ((3) (4)).
It seems natural to express this in two procedures. First, a combinations procedure:
(define (combinations xss)
(cond ((null? xss) '())
((null? (cdr xss))
(map list (car xss)))
(else
(prepend-each (car xss)
(combinations (cdr xss))))))
Now a prepend-each procedure is needed:
(define (prepend-each xs yss)
(apply append
(map (lambda (x)
(map (lambda (ys)
(cons x ys))
yss))
xs)))
Here the procedure prepend-each takes a list xs and a list of lists yss and returns the result of prepending each x in xs to the lists in yss. The inner map takes each list ys in yss and conses an x from xs onto it. Since the inner mapping produces a list of lists, and the outer mapping then produces a list of lists of lists, append is used to join the results before returning.
combinations.rkt> (combinations '((1 2) (3 4) (5 6)))
'((1 3 5) (1 3 6) (1 4 5) (1 4 6) (2 3 5) (2 3 6) (2 4 5) (2 4 6))
Now that a working approach has been found, this could be converted into a single procedure:
(define (combinations-2 xss)
(cond ((null? xss) '())
((null? (cdr xss))
(map list (car xss)))
(else
(apply append
(map (lambda (x)
(map (lambda (ys)
(cons x ys))
(combinations-2 (cdr xss))))
(car xss))))))
But, I would not do that since the first version in two procedures seems more clear.
It might be helpful to look just at the results of prepend-each with and without using append:
combinations.rkt> (prepend-each '(1 2) '((3 4) (5 6)))
'((1 3 4) (1 5 6) (2 3 4) (2 5 6))
Without using append:
(define (prepend-each-no-append xs yss)
(map (lambda (x)
(map (lambda (ys)
(cons x ys))
yss))
xs))
combinations.rkt> (prepend-each-no-append '(1 2) '((3 4) (5 6)))
'(((1 3 4) (1 5 6)) ((2 3 4) (2 5 6)))
It can be seen that 1 is prepended to each list in ((3 4) (5 6)) to create a list of lists, and then 2 is prepended to each list in ((3 4) (5 6)) to create a list of lists. These results are contained in another list, since the 1 and 2 come from the outer mapping over (1 2). This is why append is used to join the results.
Some Final Refinements
Note that prepend-each returns an empty list when yss is empty, but that a list containing the elements of xs distributed among as many lists is returned when yss contains a single empty list:
combinations.rkt> (prepend-each '(1 2 3) '(()))
'((1) (2) (3))
This is the same result that we want when the input to combinations contains a single list. We can modify combinations to have a single base case: when the input is '(), then the result is (()). This will allow prepend-each to do the work previously done by (map list (car xss)), making combinations a bit more concise; the prepend-each procedure is unchanged, but I include it below for completeness anyway:
(define (combinations xss)
(if (null? xss) '(())
(prepend-each (car xss)
(combinations (cdr xss)))))
(define (prepend-each xs yss)
(apply append
(map (lambda (x)
(map (lambda (ys)
(cons x ys))
yss))
xs)))
Having made combinations more concise, I might be tempted to go ahead and write this as one procedure, after all:
(define (combinations xss)
(if (null? xss) '(())
(apply append
(map (lambda (x)
(map (lambda (ys)
(cons x ys))
(combinations (cdr xss))))
(car xss)))))

Scheme: Update a list without using imperative features like set

I have only just started to learn scheme and were asked to implement the quick-sort algorithm in scheme, but we are not allow to use any imperative features like set! and we are not allowed to use filter
I have tried to come up with my own algorithm with this in mind, but I can't seem to avoid the use of set! for updating a list:
(define quicksort
(lambda (L)
(cond
[(or (null? L) (null? (cdr L))) L]
[else (let ((pivot (car L)) (small '()) (large '()))
(do ((i (- (length L) 1) (- i 1)))
((= i 0))
(if (< (list-ref L i) pivot)
(set! small (cons (list-ref L i) small))
(set! large (cons (list-ref L i) large))))
(append (quicksort small) (list pivot) (quicksort large)))])))
This code works, but is there any way of updating the lists small and large without the use of set?
If you cannot use set!, you cannot mutate lists. You are being asked to do this functionally, without any mutation. Instead of modifying a list in-place, build up smaller, partially-sorted lists and then combine them while preserving the sort.
To be fair Quicksort is an in place algorithm and many would state replacing the vectors with lists will change it enough to no longer bee quicksort. I'll ignore this at the moment.
Split large stuff in smaller chunks of code. This way you can test each step:
(segment 5 '(5 1 1 3 8 6 4 9 8 5 3 5 3 8 6))
; ==> ((1 1 3 4 3 3) (5 5) (8 6 9 8 8 6))
Of course you make the simple tests first:
(segment 5 '(5)) ; ==> (() (5) ())
(segment 5 '(5 1)) ; ==> ((1) (5) ())
(segment 5 '(5 8)) ; ==> (() (5) (8))
(segment 5 '(5 8 1 5)) ; ==> ((1) (5 5) (8))
The order of the results in the sub list is not important. eg. the result ((3 3 4 3 1 1) (5 5) (6 8 8 9 6 8)) is equally as sufficient and most probably easier to do.
With that made quicksort by first checking if it is a less than 2 element list eg. (or (null? lst) (null? (cdr lst))) and return the argument or create the 3 segments using the first element as pivot and then append the recursion of the lesser and the higher and then appending the 3 lists together and you have them in order.
As inspiration here is a procedure that splits on odd? and not:
(define (split-odd lst)
(let loop ((lst lst) (odd '()) (even '()))
(cond
((null? lst) (list odd even))
((odd? (car lst)) (loop (cdr lst) (cons (car lst) odd) even))
(else (loop (cdr lst) odd (cons (car lst) even))))))
(split-odd '(1 2 3 4 5 6))
; ==> ((5 3 1) (6 4 2))

Scheme - Adding a list to a list of lists?

I am trying to answer a scheme question, for a part of this question I have to make a list of lists:
(define (join a b (result '()))
(cons (list a b) result))
So I am taking in two characters, and placing them in a list, then I need to place each sublist into a list of lists, this function is being called recursively with two characters each time, so it is supposed to work like this:
join 1 4
=> ((1 4))
join 2 5
=> ((1 4) (2 5))
join 3 6
=> ((1 4) (2 5) (3 6))
However, I am getting ((3 6) (2 5) (1 4)), so the elements need to be reversed, I tried reversing my cons function to (cons result (list a b)) but then I get (((() 1 4) 2 5) 3 6), how can I get the list the right way around, or is there an easier way to do what I'm doing?
If you need to add elements at the end of a list use append; cons is for adding elements at the head. Try this:
(define (join a b (result '()))
(append result (list (list a b))))
Notice that append combines two lists, that's why we have to surround the new element inside its own list. Also, it's not a good idea to add elements at the end, using append is more expensive than using cons - if possible, rethink your algorithm to add elements at the head, and reverse the result at the end.
This can easily be done like this:
(define (group-by-2 lst)
(let loop ((lst lst) (rlst '()))
(if (or (null? lst) (null? (cdr lst)))
(rcons->cons rlst)
(loop (cdr lst)
(rcons (list (car lst)
(cadr lst))
rlst)))))
(group-by-2 '(1 2 3 4 5 6 7 8))
; ==> ((1 2) (2 3) (3 4) (4 5) (5 6) (6 7) (7 8))
Now rcons is like cons but it makes a reverse list. (rcons 1 (rcons 2 (rcons 3))) ; ==> {3 2 1} however it is not a list so you have to convert it to a list (rcons->list (rcons 1 (rcons 2 (rcons 3))) ; ==> (3 2 1)
The magic functions are really not that magical:
(define rcons cons)
(define rcons->cons reverse)
So in fact I didn't really have to make that abstraction, but hopefully I made my point. It doesn't matter how you organize the intermediate data structure in your programs so why not make the best for the job you are doing. For lists it's always best to iterate from beginning to end and make from end to beginning. Every insert O(1) per element and you do a O(n) reverse in the end. It beats doing append n times that would make it O(n²)

What is the difference between `(mcons (mcons '() 25) 16)` and `(mcons 25 (mcons 16 `()))`

I am busy with Structure and Interpretation of Computer Programs exercise 2.18. Here we have to define a procedure reverse to reverse a list. It should do the following:
(reverse (list 1 4 9 16 25))
;; => (25 16 9 4 1)
I came up with the following definition:
(define (reverse list)
(if (null? list)
list
(cons (reverse (cdr list)) (car list))))
;; => (mcons (mcons (mcons (mcons (mcons '() 25) 16) 9) 4) 1).
Then in a solution In found something similar as follows:
(define (reverse items)
(if (null? (cdr items))
items
(append (reverse (cdr items))
(cons (car items) nil))))
;; => (mcons 25 (mcons 16 (mcons 9 (mcons 4 (mcons 1 '()))))).
There's a difference between append and cons here where I cannot put my finger on.
My question: what is the difference and why are the results not displayed as (25 16 9 4 1)?
Short answer: the first version of reverse is incorrectly building an improper list, the second version is inefficiently building a proper list. We can do better as long as we understand the difference between append and cons.
append concatenates two lists. If we use it for just adding an element at the end of one list, we'll be doing a lot more of work than needed: we'll have to traverse the whole list each time just to put one last element (see: Schlemiel the Painter's algorithm). Hence a reverse implementation that uses append can be as bad as O(n^2) in complexity.
On the other hand, cons adds a single element to the head of a list, for an O(n) complexity in the implementation of reverse. In general, in Scheme you should try to avoid using append to build a new output list, always prefer cons. Now let's see what's being returned by your algorithm using cons:
(reverse '(1 2 3 4 5))
=> '(((((() . 5) . 4) . 3) . 2) . 1)
Why is that? because to build a proper list with cons the second argument must be another proper list, but you're passing a single element. A correct implementation requires an accumulator parameter - and incidentally, this is more efficient, because it uses tail recursion, a concept that you should already be familiar with, as it was introduced in section 1.2 of the book. Try this:
(define (reverse lst acc)
(if (null? lst)
acc
(reverse (cdr lst) (cons (car lst) acc))))
(reverse '(1 2 3 4 5) '())
=> '(5 4 3 2 1)
For the last part of the question: the list is being displayed with mcons (the m means that the cons cells are mutable) because of the language you're using, try switching to #lang racket, which uses immutable cons cells by default, and will get printed as you expect.

search through nested list in scheme to find a number

How would I search through the nested list to find a certain number?
For example, the list is:
((1 2) (2 3) (3 4) (3 5) (4 5))
and I'm looking for 1.
Expected output:
(1 2)
since 1 is in the sub list (1 2).
First of all create function to flatten list. Something like this:
> (flatten '((8) 4 ((7 4) 5) ((())) (((6))) 7 2 ()))
(8 4 7 4 5 6 7 2)
And then search your number in the ordinary list.
This quesion looks like the homework so try to develop this function on your own and if you can not do it - post your code here and I'll try to help you.
Updated
Ok. As I understand we need to create function which get the list of pairs and return another list of pairs, where first element of pair equal some number.
For example:
(define data '((1 2)(2 3)(3 4)(3 5)(4 5)))
(solution data 3)
-> '((3 4) (3 5))
(define data '((1 2)(2 3)(3 4)(3 5)(4 5)))
(solution data 1)
-> '((1 2))
In the other words we need to filter our list of pairs by some condition. In the Scheme there is a function to filter list. It takes a list to filter and function to decide - to include or not the element of list in the result list.
So we need to create such function:
(define (check-pair num p)
(cond
[(= (first p) num) #t]
[else #f]))
This function get a pair (element of list), number and decide - incude or not this pair to result list. This function have 2 parameters, but the filter function require the function with only one parameter, so we rewrite our function such way:
(define (check-pair num)
(lambda (p)
(cond
[(= (first p) num) #t]
[else #f])))
I have created function wich produce another function. It is currying.
So, we have all to create our solution:
(define (check-pair num)
(lambda (p)
(cond
[(= (first p) num) #t]
[else #f])))
(define (solution list num)
(local
((define check-pair-by-num (check-pair num)))
(filter check-pair-by-num list)))
(define data '((1 2)(2 3)(3 4)(3 5)(4 5)))
(solution data 1)
Flattening isn't the approach I'd prefer here, but that doesn't mean it's incorrect. Here's an alternative:
(define (solve lst num)
(cond
[(null? lst) null]
[(cons? (first lst)) (solve (first lst) num)]
[(member num lst) (cons lst (solve (rest lst) num))]
[#t (solve (rest lst) num)]))
This just recursively deals with nested listing as needed, so I prefer it a little bit stylistically. In addition, the call to member can be replaced with check-pair from above, but member will let you grab values from cdrs as well as cars, if you want that.
Use find to select a member of a list meeting a condition:
(find contains-1? '((1 2)(2 3)(3 4)(5 6)))
How to implement contains-1? Hint: consider the member function:
(member 1 '(1 2)) => #t
(member 1 '(3 4)) => #f

Resources