I need to write a Scheme function that takes a list as an argument and returns a list of lists where every list is a cycle of the original list.
By a cycle, I mean shifting the first element to the last position.
I have the following functions:
(define (cycle lst)
(cond ((null? lst) '())
((null? (cdr lst)) lst)
(else (append (cdr lst) (list (car lst))))))
(define (shift lst)
(define (iter l cycles result)
(cond ((= cycles 0) (cons lst result))
((< cycles 1) result)
(else (iter (cycle-1 l) (- cycles 1) (cons result (cycle-1 l))))))
(iter lst (- (length lst) 1) '()))
Now, when I do:
(shift '(1 2 3))
I get:
'((1 2 3) (() 2 3 1) 3 1 2)
I should get:
'((1 2 3) (2 3 1) (3 1 2))
(define (shift lst)
(define (iter l cycles result)
(cond ((= cycles 0)
(cons lst result))
((< cycles 0) result)
(else (let ((cycled (cycle l)))
(iter cycled (- cycles 1) (cons cycled result))))))
(iter lst (- (length lst) 1) '()))
First, I've made a simple improvement to prevent calculate cycled form of the list twice(added let). Second, you need to cons cycled to result since you need to append result list, not cycled list. In your code, you're adding last result to old results and then passing this wrongly appended results list to iter functions as result parameter.
Update: To get the results in your order you can simple just append result with cycled list, instead of adding cycled list to head of the result:
(define (shift lst)
(define (iter l cycles result)
(cond ((= cycles 0)
(cons lst result))
((< cycles 0) result)
(else (let ((cycled (cycle l)))
(iter cycled (- cycles 1) (append result (list cycled)))))))
(iter lst (- (length lst) 1) '()))
Related
So I have to write a method that takes in a list like (nested '(4 5 2 8)) and returns (4 (5 () 2) 8).
I figured I needed to write 3 supporting methods to accomplish this. The first gets the size of the list:
(define (sizeList L)
(if (null? L) 0
(+ 1 (sizeList (cdr L)))))
input : (sizeList '(1 2 3 4 5 6 7))
output: 7
The second drops elements from the list:
(define (drop n L)
(if (= (- n 1) 0) L
(drop (- n 1) (cdr L))))
input : (drop 5 '(1 2 3 4 5 6 7))
output: (5 6 7)
The third removes the last element of a list:
(define (remLast E)
(if (null? (cdr E)) '()
(cons (car E) (remLast (cdr E)))))
input : (remLast '(1 2 3 4 5 6 7))
output: (1 2 3 4 5 6)
For the nested method I think I need to do the car of the first element, then recurse with the drop, and then remove the last element but for the life of me I can't figure out how to do it or maybe Im just continually messing up the parenthesis? Any ideas?
Various recursive solutions are possible, but the problem is that the more intuitive ones have a very bad performance, since they have a cost that depends on the square of the size of the input list.
Consider for instance this simple solution:
; return a copy of list l without the last element
(define (butlast l)
(cond ((null? l) '())
((null? (cdr l)) '())
(else (cons (car l) (butlast (cdr l))))))
; return the last element of list l
(define (last l)
(cond ((null? l) '())
((null? (cdr l)) (car l))
(else (last (cdr l)))))
; nest a linear list
(define (nested l)
(cond ((null? l) '())
((null? (cdr l)) l)
(else (list (car l) (nested (butlast (cdr l))) (last l)))))
At each recursive call of nested, there is a call to butlast and a call to last: this means that for each element in the first half of the list we must scan twice the list, and this requires a number of operations of order O(n2).
Is it possible to find a recursive solution with a number of operations that grows only linearly with the size of the list? The answer is yes, and the key to this solution is to reverse the list, and work in parallel on both the list and its reverse, through an auxiliary function that gets one element from both the lists and recurs on their cdr, and using at the same time a counter to stop the processing when the first halves of both lists have been considered. Here is a possible implementation of this algorithm:
(define (nested l)
(define (aux l lr n)
(cond ((= n 0) '())
((= n 1) (list (car l)))
(else (list (car l) (aux (cdr l) (cdr lr) (- n 2)) (car lr)))))
(aux l (reverse l) (length l)))
Note that the parameter n starts from (length l) and is decreased by 2 at each recursion: this allows to manage both the cases of a list with an even or odd number of elements. reverse is the primitive function that reverses a list, but if you cannot use this primitive function you can implement it with a recursive algorithm in the following way:
(define (reverse l)
(define (aux first-list second-list)
(if (null? first-list)
second-list
(aux (cdr first-list) (cons (car first-list) second-list))))
(aux l '()))
I want to get a list which has nth version deleted from the original list. I could manage following code which is imperative:
(define (list-removeN slist n)
(define outl '())
(for ((i (length slist)))
(when (not (= i n))
(set! outl (cons (list-ref slist i) outl))))
(reverse outl))
What can be the functional equivalent of this? I tried for/list, but I have to insert #f or at that position, removing which is not ideal because #f or may occur at other positions in list also.
You can do it recursively with an accumulator. Something like
#lang racket
(define (remove-nth lst n)
(let loop ([i 0] [lst lst])
(cond [(= i n) (rest lst)]
[else (cons (first lst) (loop (add1 i) (rest lst)))])))
(remove-nth (list 0 1 2 3 4 5) 3)
(remove-nth (list 0 1 2 3) 3)
(remove-nth (list 0 1 2) 0)
This produces
'(0 1 2 4 5)
'(0 1 2)
'(1 2)
You could do it with for/list but this version traverses the list twice because of the length call.
(define (remove-nth lst n)
(for/list ([i (length lst)]
[elem lst]
#:when (not (= i n)))
elem))
There's also split-at, but again this may not be as optimal as it creates two lists and appends them.
(define (remove-nth lst n)
(let-values ([(left right) (split-at lst n)])
(append left (rest right))))
A typical roll your own implementation that is recursive and uses O(n) time and O(n) space.
(define (remove-nth lst i)
(let aux ((lst lst) (i i))
(cond ((null? lst) '()) ;; what if (< (length lst) i)
((<= i 0) (cdr lst)) ;; what if (< i 0)
(else (cons (car lst)
(aux (cdr lst) (sub1 i)))))))
A interative version that uses append-reverse from srfi-1. O(n) time and O(1) space.
(define (remove-nth lst i)
(let aux ((lst lst) (i i) (acc '()))
(cond ((null? lst) (reverse acc)) ;; what if (< (length lst) i)
((<= i 0) (append-reverse acc (cdr lst))) ;; what if (< i 0)
(else (aux (cdr lst) (sub1 i) (cons (car lst) acc))))))
What I need to add to count the number of zeros only in the even lists?
For example,
(count-zeroes '((1 1 1) (1 0 0) (1 1 1) (1 0 0)))
4
it is for one list.
(define count-zeroes
(lambda (list)
(cond ((null? list) 0)
((= 0 (car list)) (+ 1 (count-zeroes (cdr list))))
(else (+ 0 (count-zeroes (cdr list))))
)
)
)
(define count-zeroes
(lambda (list)
(cond ((null? list) 0) ; a
((= 0 (car list)) (+ 1 (count-zeroes (cdr list)))) ; b
(else (+ 0 (count-zeroes (cdr list))))))) ; c
If list is initially a list of lists, then (null? list) in line a can be true (when you get to the end of the list), but the condition (= 0 (car list)) in the line b will never be true, since (car list) will always be another list, and 0 isn't a list.
A better way to break this down would probably be to first extract the even positioned sublists, then flatten them into a single list, and then count the zeros in those. That's not the most efficient way to do it (you'll create some intermediate storage), but you should probably implement something like that first, and then gradually optimize it afterward.
It's also worth noting that lists are typically indexed starting with position zero, so the second, fourth, etc., elements in the list are the ones with odd positions, not even positions. Here's the kind of abstraction that might help you in getting started with this kind of approach:
(define first car)
(define rest cdr)
(define list* cons)
(define (odds list)
(if (null? list) '()
(evens (cdr list))))
(define (evens list)
(if (null? list) '()
(list* (first list)
(odds (rest list)))))
(define sample '((0 0 1) (0 1 0) (0 1 1) (1 0 0) (1 0 1) (1 1 0) (1 1 1)))
;; (display (odds sample))
;; => ((0 1 0) (1 0 0) (1 1 0))
An interesting question. If you are operating on a lists of lists you need to add car-cdr recuresion.
(define (count-zeroes lst) ;;don't override core function names with a variable
(cond ((null? lst) 0)
((pair? (car lst))
(+ (count-zeroes (car lst))
(count-zeroes (cdr lst))))
((= 0 (car lst))
(+ 1 (count-zeroes (cdr lst))))
(else (count-zeroes (cdr lst))))))
No as to only evens you are no longer counting zeros, so a new function name is in order. You could make up a higher order function like this.
(define (count-zeros-of selector lst)
(count-zeroes (selector lst)))
And make a general selector
(define (take-every-Xnth-at-y x y lst)
(cond ((null? lst) '())
((= y 0) (cons (car lst)
(take-every x (- x 1) (cdr lst))))
(else (take-every x (- y 1) (cdr lst)))))
To put it all together
(define (count-zeroes-of-even lst)
(count-zeroes-of
(lambda (lst) ;;to bad we can't do partial application
(take-every-Xnth-at-y 2 1 lst))
lst)
Note each of these parts do their one thing and do it well.
My problem is the butSecondLastAtom algorithm. It doesn't work because cdr doesn't comprehend an empty list. But I see no other way of writing the algorithm. It's at the end of the page. Everything works but when the last element of a list is a list.
http://lpaste.net/110959
The problem is in the recursive call of (cdr (cdr l)) but more in the 3rd condition. Idk what to do. I'm just going to stop tonight and start fresh in the morning.
((and (isAtom (second_last_element l)) (notAtom (last_element l)))
(cons
(car l)
(butSecondLastAtom (last_element l))))
I think the main problem in your code is the use of null? or cdr on the cdr of a list, both in flatten and in butLast. Don't do this; always use the procedures and predicates on the list itself.
I'd suggest the following:
Flattening the list
Most Schemes have a version of flatten build-in, which takes care of nested lists and improper lists. The version you implemented is not entirely correct (try (flatten '())), use this one:
(define (flatten lst)
(let loop ((lst lst) (res null))
(cond
((null? lst) res)
((pair? lst) (loop (car lst) (loop (cdr lst) res)))
(else (cons lst res)))))
> (flatten '(1 2 (3 (4 5 6))))
'(1 2 3 4 5 6)
> (flatten '(1 2 (3 (4 5 (6)))))
'(1 2 3 4 5 6)
> (flatten '())
'()
Dropping the second last element
So this becomes much easier now, looping through a simple flat proper list while keeping track of the last (n-1) and second-last (n-2) element. An example implementation is:
(define (butSecondLastAtom lst)
(define flst (flatten lst))
(if (< (length flst) 2)
flst
(let loop ((flst (cddr flst)) (n-2 (car flst)) (n-1 (cadr flst)) (res null))
(if (null? flst)
(reverse (cons n-1 res)) ; here we drop the second-last element
(loop (cdr flst) n-1 (car flst) (cons n-2 res))))))
If you want to avoid going through the list twice (once for length, once for the loop), you can also keep track of the length yourself:
(define (butSecondLastAtom lst)
(define flst (flatten lst))
(let loop ((lst flst) (len 0) (n-2 #f) (n-1 #f) (res null))
(if (null? lst)
(if (< len 2)
flst
(reverse (cons n-1 res))) ; here we drop the second-last element
(loop (cdr lst) (add1 len) n-1 (car lst) (if (< len 2) null (cons n-2 res))))))
Testing
> (butSecondLastAtom '(1 2 (3 (4 5 6))))
'(1 2 3 4 6)
> (butSecondLastAtom '(1 2 (3 (4 5 (6)))))
'(1 2 3 4 6)
> (butSecondLastAtom '(((a))))
'(a)
> (butSecondLastAtom '())
'()
I'm working on implementing a bubble sorting algorithm in Scheme, and I must say that the functional way of programming is a strange concept and I am struggling a bit to grasp it.
I've successfully created a function that will bubble up the first largest value we come across, but that's about all it does.
(bubbleH '(5 10 9 8 7))
(5 9 8 7 10)
I am struggling with the helper function that is required to completely loop through the list until no swaps have been made.
Here's where I am at so far, obviously it is not correct but I think I am on the right track. I know that I could pass in the number of elements in the list myself, but I am looking for a solution different from that.
(define bubbaS
(lambda (lst)
(cond (( = (length lst) 1) (bubba-help lst))
(else (bubbaS (bubba-help lst))))))
Using the bubble-up and bubble-sort-aux implementations in the possible-duplicate SO question I referenced...
(define (bubble-up L)
(if (null? (cdr L))
L
(if (< (car L) (cadr L))
(cons (car L) (bubble-up (cdr L)))
(cons (cadr L) (bubble-up (cons (car L) (cddr L)))))))
(define (bubble-sort-aux N L)
(cond ((= N 1) (bubble-up L))
(else (bubble-sort-aux (- N 1) (bubble-up L)))))
..., this is simple syntactic sugar:
(define (bubbleH L)
(bubble-sort-aux (length L) L))
With the final bit of syntactic sugar added, you should get exactly what you specified in your question:
(bubbleH '(5 10 9 8 7))
=> (5 7 8 9 10)
You can tinker with everything above in a repl.it session I saved & shared.
Here's my own tail-recursive version.
The inner function will bubble up the largest number just like your bubbleH procedure. But instead of returning a complete list, it will return 2 values:
the unsorted 'rest' list
the largest value that has bubbled up
such as:
> (bsort-inner '(5 1 4 2 8))
'(5 2 4 1)
8
> (bsort-inner '(1 5 4 2 8))
'(5 2 4 1)
8
> (bsort-inner '(4 8 2 5))
'(5 2 4)
8
Now the outer loop just has to cons the second value returned, and iterate on the remaining list.
Code:
(define (bsort-inner lst)
(let loop ((lst lst) (res null))
(let ((ca1 (car lst)) (cd1 (cdr lst)))
(if (null? cd1)
(values res ca1)
(let ((ca2 (car cd1)) (cd2 (cdr cd1)))
(if (<= ca1 ca2)
(loop cd1 (cons ca1 res))
(loop (cons ca1 cd2) (cons ca2 res))))))))
(define (bsort lst)
(let loop ((lst lst) (res null))
(if (null? lst)
res
(let-values (((ls mx) (bsort-inner lst)))
(loop ls (cons mx res))))))
For a recursive version, I prefer one where the smallest value bubbles in front:
(define (bsort-inner lst)
; after one pass, smallest element is in front
(let ((ca1 (car lst)) (cd1 (cdr lst)))
(if (null? cd1)
lst ; just one element => sorted
(let ((cd (bsort-inner cd1))) ; cd = sorted tail
(let ((ca2 (car cd)) (cd2 (cdr cd)))
(if (<= ca1 ca2)
(cons ca1 cd)
(cons ca2 (cons ca1 cd2))))))))
(define (bsort lst)
(if (null? lst)
null
(let ((s (bsort-inner lst)))
(cons (car s) (bsort (cdr s))))))