Create a partition of list into three parts in scheme - list

I am trying to find a way to split a list up into three parts. I have used a helper function and the parameters should be as follows: It evaluates to a list of three lists, containing 1) the items in the list less than pivot, 2) the items in the list equal to pivot, and 3) the items in the list greater than pivot.
(define (partition lst item)
(define (partition-iter lst less same greater)
(cond ((null? lst)(list less same greater ))
((< (car lst) item)(partition-iter (cdr lst)
(cons (car lst) less)
same
greater ))
((= (car lst) item)
less
(cons (car lst) same)
(else
(partition-iter (cdr lst) (cons (car lst) greater))))))
(partition-iter lst '() '() '()))
everything up to the else clause should work but after that i'm stuck. Any help is appreciated

The current helper function, partition-iter, will not work due to some severe mistakes in its design. But first, let me provide two versions which work:
The first (simple) version,
#lang racket
; LoN = List-of-Numbers
; partition :: LoN Number -> List-of-LoN
(define (partition1 lst pivot)
(local([; auxiliary function
; part :: LoN LoN LoN LoN -> List-of-LoN
define (part xs LT EQ GT)
; if empty list
(if (null? xs) (list LT EQ GT)
;else
(let* ([head (first xs)]
[tail (rest xs)]
[prtd (part tail LT EQ GT)]
[LT* (first prtd)]
[EQ* (second prtd)]
[GT* (third prtd)])
;--in--
(cond
; if x < pivot, add the element to LT
[(< head pivot) (list {cons head LT*} EQ* GT*)]
; if x = pivot, add the element to EQ
[(= head pivot) (list LT* {cons head EQ*} GT*)]
; if x > pivot, add the element to GT
[else (list LT* EQ* {cons head GT*})]
)
) ) ]
)
;--in--
(part lst null null null)
)
)
The second version, which is closer to your implementation, but uses fold:
#lang racket
; partition :: LoN Number -> List-of-LoN
(define (partition2 lst pivot)
(local([; auxiliary function
; part :: LoN LoN LoN LoN -> List-of-LoN
define (part x LT-EQ-GT)
(local ([define-values (LT* EQ* GT*) (apply values LT-EQ-GT)])
;--in--
(cond
; if x < pivot, add the element to LT
[(< x pivot) (list {cons x LT*} EQ* GT*)]
; if x = pivot, add the element to EQ
[(= x pivot) (list LT* {cons x EQ*} GT*)]
; if x > pivot, add the element to GT
[else (list LT* EQ* {cons x GT*})]
)
) ]
)
;--in--
(foldr part '(() () ()) lst)
)
)
Try eg.,
(partition2 '(1 2 3 4 4 3 4 5 6) 4) ;; yields '((1 2 3 3) (4 4 4) (5 6)).
Notice that the second (fold-) version is faster (and better imo).
Finally, your implementation has mistakes in the following lines (line-numbering begins at 1):
-- lines 4-7 should be:
(partition-iter (cdr lst) (cons (car lst) less) same greater)
-- lines 9-10 should be:
(partition-iter (cdr lst) less (cons (car lst) same) greater)
-- line 12 should be:
(partition-iter (cdr lst) less same (cons (car lst) greater))
Finally, with your current implementation, you should use foldl or foldr (or something like that) in your last line.

Here's you code, indented so that the corresponding items are visually aligned:
(define (partition lst item)
(define (partition-iter lst less same greater)
(cond
((null? lst)
(list less same greater ))
((< (car lst) item)
(partition-iter (cdr lst)
(cons (car lst) less)
same
greater))
((= (car lst) item)
less
(cons (car lst) same)
(else
(partition-iter (cdr lst)
(cons (car lst) greater))))))
(partition-iter lst '() '() '()))
I think you can see there's something wrong with it right away, now. It's asymmetrical, all out of wack, even if the parens are balanced. An else clause inside another cond clause? What is that??
The moral is, don't be afraid to use white space to see better. Lots and lots of white space.
Without it, Scheme tends to look like an impenetrable wall of words, parens or no parens. And the recommended indentation style. Does. Not. Help.
The fix is obvious, minimal, and simple: just complete the code in the same style you (??) started writing it. Handle the other two cases, building the three interim lists while iterating along the input list by taking repeated cdrs in each of the three cases:
(define (partition lst item)
(define (partition-iter lst less same greater)
(cond
((null? lst)
(list less same greater ))
((< (car lst) item)
(partition-iter (cdr lst)
(cons (car lst) less)
same
greater ))
((= (car lst) item)
(partition-iter (cdr lst)
less
(cons (car lst) same)
greater ))
(else ; (> (car lst) item) ; keep it here for documentation!
(partition-iter (cdr lst)
less
same
(cons (car lst) greater) )) ))
(partition-iter lst '() '() '()))
I don't even have to load it into DrRacket now to see that it's alright.
Symmetry is beautiful. Symmetry is right.
BTW, in a pattern-matching pseudocode with guards, it could be written as
partition lst item = partition-iter lst [] [] []
where
partition-iter [] less same greater = [less, same, greater]
partition-iter [a, ...lst] less same greater
| a < item = partition-iter lst [a, ...less] same greater
| a == item = partition-iter lst less [a, ...same] greater
| else = partition-iter lst less same [a, ...greater]
which I think is much more visually apparent. Going back and forth between it and the proper Scheme is a matter of purely syntactical transformations.

Related

Counting number of zeroes in lists in scheme

(define (num-zeroes lst)
(define (helper lst sofar)
(cond ((null? lst) sofar)
((list? (car lst)) (helper (car lst) sofar))
((eq? lst 0) (helper (cdr lst) (+ 1 sofar)))
(else
(helper (cdr lst) sofar))))
(helper lst 0))
This function is suppose to count the number of 0s in a list. However, it keeps giving me 0 when I input values. How would I be able to fix this?
In your third condition you are comparing lst to 0. This should be (car lst).
Because of your (list? (car lst)) condition it looks like you want to count nested lists. There is an issue with this in the current implementation (with the above check fixed) since the conditional does not add up separate parts of the list.
E.g.,
(num-zeroes '(0 0 (1 0) (1 0 0))) ; => 3
To fix this you can do something like this:
(define (num-zeroes lst)
(define (helper lst sofar)
(cond ((null? lst) sofar)
((list? (car lst)) (+ sofar ;; add sofar to
(helper (car lst) 0) ;; branched out first part
(helper (cdr lst) 0))) ;; and branched rest
((eq? (car lst) 0) (helper (cdr lst) (+ 1 sofar))) ;; (car lst), not lst
(else
(helper (cdr lst) sofar))))
(helper lst 0))
This leads to:
(num-zeroes '(0 0 (1 (1 (0 0) 0)) (1 0 0))) ;; => 7
Now, variations on your problem where you want to do something over a collection and keep an accumulated value happen a lot. fold is a higher-order function that is designed specifically for these problems.
Fold takes a function with two arguments (an element and an accumulator), a starting value and a collection. It successively applies the function to each element of the collection and at the end returns the accumulator.
In your case it's possible to only add 1 to the accumulator when the element is 0, and pass a flattened list (flatten removes the nesting from a list) to foldl (see https://docs.racket-lang.org/reference/pairs.html#%28def._%28%28lib._racket%2Fprivate%2Flist..rkt%29._foldl%29%29) (the l means it walks the list from left to right) to deal with nesting:
(define (num-zeroes2 lst)
(foldl (lambda (e acc)
(if (= e 0)
(+ acc 1)
acc))
0
(flatten lst)))
This leads to the same result:
(num-zeroes2 '(0 0 (1 (1 (0 0) 0)) (1 0 0))) ;; => 7
Or, thinking about it, you can also flatten the list and filter out all values equal to 0 (there is a library method called zero? for that), and count the elements:
(define (num-zeroes3 lst)
(length
(filter zero? (flatten lst))))
Hope this helps.

Transpose list of tuples filling with empty lists

I'm new to Scheme and I'm trying to write a procedure which combines n list into a list of n-tuples. If the lists are of different size, the tuples should contain the empty list () when the corresponding list ran out of elements.
My current implementation is the following:
(define (comb list1 list2)
(cond [(empty? list1) empty]
[(empty? list2) empty]
[else (cons (list (first list1) (first list2))
(comb (rest list1) (rest list2)))]))
However, this program doesn't produce another tuple when there are no more items in the list to combine. For instance, (comb '(1 2 3 ) '(3 4)) produces only ((1 3) (2 4))
How do I solve it?
This is a bit tricky, and I believe it's not an appropriate exercise for someone who is just learning the basics of the language. Anyway, here's my proposed solution, in terms of higher-order procedures:
; helper procedure for filling a list with arbitrary values at the end
(define (fill lst val num)
(append lst
(build-list num (const val))))
; helper procedure for transposing a list of lists
(define (transpose lsts)
(apply map list lsts))
; main procedure
(define (list-tuples lsts)
(let* ((lengths (map length lsts)) ; obtain the length of each sublist
(max-length (apply max lengths))) ; find out the maximum length
(transpose ; build new sublists element-wise
(map (lambda (lst len) ; build sublists of the right length
(fill lst '() (- max-length len))) ; fill sublists with '()
lsts
lengths))))
The trick was to find the maximum length of the lists and then build new lists with that length, filling them with '() at the end. After that, it's a simple matter of building the answer by taking one element from each sublist. It works as expected:
(list-tuples '((m n o) (1) (x y)))
=> '((m 1 x) (n () y) (o () ()))
You need to specifically deal with the situation where one of the lists is empty. The following does what I think you want with two lists.
(define (comb l1 l2)
(cond
((empty? l1)
(cond
((empty? l2) '())
(else (cons (list '() (car l2)) (comb l1 (cdr l2))))))
(else
(cond
((empty? l2) (cons (list (car l1) '()) (comb (cdr l1) l2)))
(else (cons (list (car l1) (car l2)) (comb (cdr l1) (cdr l2))))))))
Let's split the problem into 2 parts.
First let's assume a procedure that will take a list, and return the following results:
a list containing the first items of each sublist
a list containing the remainder of each sublist
the number of non-empty lists encountered
An example implementation could be:
(define (split-tuples lst)
(let loop ((lst lst) (fst null) (rst null) (cnt 0))
(if (null? lst)
(values (reverse fst) (reverse rst) cnt)
(let ((c (car lst)))
(if (null? c)
(loop (cdr lst) (cons c fst) (cons c rst) cnt)
(loop (cdr lst) (cons (car c) fst) (cons (cdr c) rst) (add1 cnt)))))))
Testing:
> (split-tuples '((m n o) (1) (x y)))
'(m 1 x)
'((n o) () (y))
3
> (split-tuples '((n o) () (y)))
'(n () y)
'((o) () ())
2
> (split-tuples '((o) () ()))
'(o () ())
'(() () ())
1
> (split-tuples '(() () ()))
'(() () ())
'(() () ())
0
Now using this procedure we create the main procedure that will just loop until all sublists are empty:
(define (list-tuples lst)
(let loop ((lst lst) (res null))
(let-values (((fst rst cnt) (split-tuples lst)))
(if (zero? cnt)
(reverse res)
(loop rst (cons fst res))))))
Testing:
> (list-tuples '((m n o) (1) (x y)))
'((m 1 x) (n () y) (o () ()))
> (list-tuples '())
'()

Using a single function to find min and max numbers in a list without using a driver function?

I am currently confused with the idea behind functional programming in general. I currently have a working solution to my problem (That is, finding the min and max of a list, and returning these in a new list) but to do that, my solution essentially requires 3 functions, and this bothers me, because I am sure there is a way to do it with just 1 function in scheme.
So.. my question is, how do I combine the outputs of 2 functions into 1 concise function? (The driver function)
Here is what I have...
(define (findMax lst) ; Find and return maximum number in a list
(cond [(null? lst) '()]
[(= (length lst) 1) (list-ref lst 0)]
[(> (list-ref lst 0) (list-ref lst (- (length lst) 1))) (findMax (drop-right lst 1))]
[(< (list-ref lst 0) (list-ref lst (- (length lst) 1))) (findMax (cdr lst))]
(else
(findMax (cdr lst))
)
)
)
(define (findMin lst) ; Find and return smallest number in a list
(cond [(null? lst) '()]
[(= (length lst) 1) (list-ref lst 0)]
[(> (list-ref lst 0) (list-ref lst (- (length lst) 1))) (findMin (cdr lst))]
[(< (list-ref lst 0) (list-ref lst (- (length lst) 1))) (findMin (drop-right lst 1))]
(else
(findMin (cdr lst))
)
)
)
I use a driver function to take both of these functions, and make a new list shown here:
(define (findEnds lst)
(list (findMin lst) (findMax lst))
)
So essentially, if given a list:
(6 7 8 4 9 2)
the output would be:
(2 9)
I know there is some way to use lambda possibly to do all of this in 1 function, but I need to be pointed in the right direction. Thanks!
Here's my version (note that I've changed it to return the result as a single dotted pair, rather than a list with two elements†):
(define (min/max lst)
(if (empty? lst)
#f
(let ((next (min/max (cdr lst))))
(define cur (car lst))
(if (not next)
(cons cur cur)
(cons (min (car next) cur) (max (cdr next) cur))))))
Example:
> (min/max '(3 1 4 1 5 9))
(1 . 9)
† If you really want to use a list of two elements, change all the cons to list, and change the (cdr next) to (cadr next).
This is actually a really good challenge that might help with learning some Scheme concepts. I've implemented min/max using fold-left. It might also be fun using a named-let
(define (min/max lst)
(fold-left
(lambda (acc num)
(cons (min num (car acc)) (max num (cdr acc))))
(cons +inf.0 -inf.0)
lst))

Finding the occurence element in the list in racket

Assume (list "apple" "orange" "apple" "grape" "orange")and produce (list (list 2 "apple") (list 2 "orange") (list 1 "grape")).
The most common fruit will occur first in the produced list.
In the case of ties, order the tied pairs with the fruit in increasing alphabetical order.
use abstract list function such as map,filter, foldr and quicksort in local. no recursion.
i'm not sure how to do it without recursion.
i wrote like this:
(define (function list)
(cond
[(empty? list) empty]
[else
(local
(define (helper1 a b)
(cond
[(equal? a b) a]
[else b]))
(define T (foldr helper1 (first list) (rest list)))
(define (count a)
(cond
[(equal? a T) true]
[else false]))
(define new-list (quicksort (length (filter count list)) >))]
The most efficient way is to use a (mutable) hash table:
(define (count-by-type lst)
; create hash
(define h (make-hash))
; update hash, creating entries if needed, otherwise adding 1 to existing entry
(map (lambda (e) (hash-update! h e add1 0)) lst)
; create list of (count key) elements from hash and sort accordingly
(sort (map (lambda (e) (list (cdr e) (car e))) (hash->list h))
(lambda (x y) (or (> (car x) (car y))
(and (= (car x) (car y)) (string<? (cadr x) (cadr y)))))))
testing:
> (count-by-type (list "apple" "orange" "apple" "grape" "orange"))
'((2 "apple") (2 "orange") (1 "grape"))
I just rehashed my own answer from a previous question. This seems to be a similar assignment, but without struct
Using a hash you could do it with only one pass through the unsorted list, then produced a list that then was sorted with a special <-function that sorts by count, then fruit.
These hints are for a functional solution. First sort the argument (sort list-of-fruits string>?). that the in descending order and oposite of your result. .
Given the list has at least one element:
(let rec ((cur (car sorted-fruits)) (cnt 1) (lst (cdr sorted-fruits)) (acc '()))
(cond ((equal? cur (car lst)) (rec cur (add1 cnt) (cdr lst) acc))
(else (rec (car lst) 1 (cdr lst) (cons (list cnt cur) acc)))))
This will produce a list in ascending order with counts.
If you sort again:
(sort list-of-counts-and-fruit (lambda (x y) (>= (car x) (car y)))
sort in Racket is stable. That means if you have two with equal counts in the list they will end up in their original order. The original order was the ascending animal order so the result is ordered by count descending, then name ascending.
I guess your procedure can be made by chaining these together, perhaps using let to store intermediates to make expressions shorter and more readable.

Way of returning median value of a list? (scheme)

I'm attempting to make a procedure named median that takes the median value of a list. If the list is even, then I will return the two middle numbers. I have the logic all thought out in my head, but I'm not sure how to complete it. NOTE: I am trying to avoid using list-ref, as it would trivialize the problem.
So far, my code looks like the following.
(define (median lst)
(if (null? lst)
'()
(if (even? lst) ; ends here
Now, my approach to the problem is this.
Odd #- Return the value of the "car#" that's in place of (/ (+ (length lst) 1) 2)
3; 2nd car (1 100 3) => 100
5; 3rd car (1 2 100 4 5) => 100
7; 4th car (1 2 3 100 5 6 7) => 100
Even # - Return the value of the "car#" that's in place of (/ (length lst) 2) AND (+ (/ (length lst) 2) 1)
2; 1st and 2nd car (1 2) => 1 2
4; 2nd and 3rd car (1 20 30 4) => 20 30
However, I cant seem to come up with a way that could recursively implement this pseudocode.
EDIT: Not sure if anyone is still out there willing to help, but I ended up writing an iterative procedure that will take the median index value for any odd list. My trouble now is implementing something that will make the code work for an even list, and also something that doesn't return the value in a list:
(define (median-index-odd lst)
(define (median-index-iter1 lst times_carred)
(if (null? lst)
'()
(if (= times_carred (/ (+ (length lst) 1) 2))
(list (car lst))
(median-index-iter1 (cdr lst) (+ 1 times_carred)))))
(median-index-iter1 lst 0))
I've also came up with a seperate procedure for finding the median index when the list is even:
(define (median-index-even lst)
(define (median-index-iter2 lst times_carred)
(if (null? lst)
'()
(if (= times_carred (/ (length lst) 2))
(list (car lst) (cadr lst))
(median-index-iter2 (cdr lst) (+ 1 times_carred)))))
(median-index-iter2 lst 0))
Seems like homework.
The straightforward solution includes list-sort (rnrs / sorting) unless it's already sorted, length to get the list length, list-tail to get the list from half and car for odd, and an additional cadr for the even list. You use let to do something with intermediate values.
Edit in some code even if you get it right or not. For the latter we can help you more.
(define (median L)
(if (null? L)
(error "No median of empty list")
(let loop ((L1 L) (L2 L))
(cond ((null? (cdr L2)) (car L1))
((null? (cddr L2)) (list (car L1) (cadr L1)))
(else (loop (cdr L1) (cddr L2))))))
split into two lists take the first one at a time, the second two at a time