Scheme - Adding a list to a list of lists? - scheme

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

Related

Possible position of element in list using recursion?

Can anybody tell how to insert an element in the list in different positions and return a list of those possible combination as lists using only recursion?
For example, list is (2 3) and element to insert is 1.
Output:
list(
list (1 2 3)
list (2 1 3)
list (2 3 1)
)
The first step is to determine what the output should look like, and in this case it should be a list of lists.
The second step is usually to break the problem down into cases of the input list.
The case of the empty list is pretty simple - the result is a list that contains one singleton list
(define (insert i ls)
(if (null? ls)
(list (list i))
(...)))
For the case of the non-empty list, it's helpful to examine the structure of the expected result.
(insert 1 '(2 3))
-->
((1 2 3) (2 1 3) (2 3 1))
Note that only the first element of the result has 1 as its first element, and we can easily create this with (cons 1 '(2 3)).
The other elements all have the first element of the input list as their first element, and if you look at their tails, (1 3) and (3 1), you'll see that they are the results of the recursion (insert 1 '(3)).
What's missing is that you need to cons the 2 onto each one of them afterwards.
Now we have all the necessary parts - in summary
(define (insert i ls)
(if (null? ls)
(list (list i))
(cons (cons i ls) (<...something...> (insert i (cdr ls))))))
Where I've left a "<...something...>" part for you to figure out.

Reversing list with sublists and atoms in lisp

I am new to a functional programming and trying to reverse a list in lisp. List consists of sublists and atoms. The function (reverse-tree '((1 2) 5 6 (3))) should return ((3) 6 5 (2 1)). Here is my function:
(define (reverse-tree s)
;; giving problem with an atom
(if (not(list? s)) ( reverse-tree s) (reverse (map reverse s)))
)
It works when I do (reverse-tree '((1 2) (3))) => ((3) (2 1)). But it crashes when I do (reverse-tree '((1 2) 5 6 (3))). The error I am getting is reverse: contract violation expected: list?
I am limited to use only: reverse, map, if, cond, list? null? functions.
EDIT, someone marked this question as duplicate, but there is a restriction in this problem, which is not similar to the other question. I cannot use cons, car, cdr, append. Any suggestions?
Think about the problem in pieces. First, if the function is given a list as an argument, you need to reverse that list. That's easy, something like:
(define (reverse-tree tree)
(if (list? tree)
(reverse tree)
...))
But you also need to reverse all sublists in it and all sublists in them and so on. Since that's exactly what our reverse-tree does, we should use map to apply it to all elements in the reversed list (it doesn't actually matter whether you use map before or after reversing the list):
(define (reverse-tree tree)
(if (list? tree)
(map reverse-tree (reverse tree))
...))
But if the input is ((1 2) 3 4 (5 6)), the map will call reverse-tree on the atoms 3 and 4 too. It wouldn't make any sense to reverse them, so we can just return them:
(define (reverse-tree tree)
(if (list? tree)
(map reverse-tree (reverse tree))
tree))
Now it should work:
(reverse-tree '((1 2) 3 4 (5 6)))
;=> ((6 5) 4 3 (2 1))
(reverse-tree '((1 2) 3 4 (5 6 (7 8))))
;=> (((8 7) 6 5) 4 3 (2 1))

How to use foldr in scheme?

When you use foldr, the procedure you use has 2 arguments, the current value of the list and the accumulator. Let's say the list you iterate over is a list of list of numbers, all the same length. Then as you iterate through them, you want to multiply the numbers of the same index and store it as the accumulator.
If you use lambda (x acc) (map * x acc) inside the foldr, this fails because acc I believe is an empty list in the beginning. How can you handle the base case like this?
This can be solved using foldr all right, the trick is to correctly initialize the accumulated value at the beginning. No need to do fancy stuff (like macros) here!
(define lst '((1 2 3) (2 3 5) (3 5 7)))
(foldr (lambda (x acc) (map * x acc))
(car lst)
(cdr lst))
=> '(6 30 105)
Of course, if the list is empty (car lst) will fail. So you might want to handle the empty list as a separate case before invoking foldr.
Say you have a list of lists as follows:
((1 2 3) (2 3 5) (3 5 7))
You want to reduce it to:
(6 30 105)
I would simple do:
(define-syntax mul
(syntax-rules ()
((_ (lists ...)) (map * 'lists ...))))
The you can use it as follows:
(mul ((1 2 3) (2 3 5) (3 5 7))) ; => (6 30 105)
The above code simply expands to:
(map * '(1 2 3) '(2 3 5) '(3 5 7))
Then you can fold the resulting list. For example:
(foldr + 0 (mul ((1 2 3) (2 3 5) (3 5 7)))) ; => 141

How to count individual elements in a pair - scheme ?

(cons 2 (cons ( cons 2 3 ) (cons 4 5 )))
This gives me a list that looks like this : (2 (2 . 3) 4 . 5) when I try to count the number of elements in this list the output is 3 as exepected.
How do I calculate the number of individual elements of a pair ? The output in this case should be 5 for example.
Here's a possible solution, the question is essentially asking for the number of atoms in a list structure (not necessarily null-terminated proper lists):
(define (count-all seq)
(cond ((null? seq) 0)
((not (pair? seq)) 1)
(else (+ (count-all (car seq))
(count-all (cdr seq))))))
It works on sequences of elements like this:
If the sequence is empty, it has zero elements
If the sequence is not a cons cell (a pair of elements), it's because it's a single element - an atom
Otherwise add the elements of both the car and the cdr of the sequence
It works as expected for arbitrarily nested list structures:
(count-all '(2 (2 . 3) 4 . 5))
=> 5
(count-all '(1 (2 . (3 (4 . 5) 6)) 7 . 8))
=> 8
We can solve this problem recursively for arbitrarily deeply nested lists.
(define (atom? x) (not (pair? x)))
(define (count-atoms lst)
(cond ((null? lst) 0) ; nothing to count, return 0
((atom? lst) 1) ; lst contains only one thing, return 1
(else ; otherwise, lst contains multiple elements
(+ (count-atoms (car lst)) ; add the number of atoms in the first position
(count-atoms (cdr lst)))))) ; to the number of atoms in the rest of the list
EDIT: This is a duplicate to Oscar's answer. I did not see that he had answered when I hit submit, but will leave this here since I feel the comments are useful.

Modify part of list using set?

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.

Resources