Longest subset of numbers in Scheme [duplicate] - functional-programming

Statement: Sind the longest chain of character and return it.
Ex: input: '(1 2 2 3 3 3 4 4 4 4 5 6 )
ouput: '(4 4 4 4)
Problem: I can manage to identify all the different groups in the list and compare them but can't get the function to return the right subset list. It only returns the last group analyzed.
code:
(define finalL (list))
(define (sameNum liste)
(if (or (null? liste) (null? (cdr liste)))
;; true
'()
;; false
(let ([lcdr (sameNum (cdr liste))])
(if (eqv? (car liste) (car(cdr liste)) )
;; true
(if (= (length liste) 2)
;; true
(cons (car liste) (cons (car(cdr liste)) lcdr))
;; false
(if (or (not(eqv? (car(cdr liste)) (car(cdr (cdr liste))) )) (null? (cdr liste)) )
(cons (car liste) (cons (car(cdr liste)) lcdr)) ;true
(cons (car liste) lcdr))) ; false
;; false
(if (let ((x (length lcdr)) (y (length finalL))) (< x y))
;; true
(crushL finalL lcdr)
;; false
finalL)))))
;; crush L1 and replace by value of L2
(define (crushL L1 L2)
(if (null? L1)
;; true
(cons L2 L1)
;; false
(crushL (cdr L1) L2)))

The trick is to keep four things as you walk down the list:
the current chain (note: you can build these backwards, since all the elements are the same!);
how long it is;
the longest chain you've seen;
how long that was.
Then you make decisions based on whether the element you are looking at is the same as the first element in the current chain (still building the same chain) or not (starting a new chain) and, if you are still building the same chain, whether that chain is now the longest.
Like this:
(define (longest-chain l)
(let lc-loop ([tail l]
[current-length 0]
[current-chain '()]
[longest-length 0]
[longest-chain '()])
(cond [(null? tail)
;; we're done: return the longest chain
longest-chain]
[(and (not (null? current-chain))
(eqv? (first tail) (first current-chain)))
;; building on a current chain
(let ([chain (cons (first tail) current-chain)]
[chain-length (+ 1 current-length)])
(if (> chain-length longest-length)
;; the current chain is now the longest
(lc-loop (rest tail)
chain-length chain
chain-length chain)
;; it's not the longest yet
(lc-loop (rest tail)
chain-length chain
longest-length longest-chain)))]
[else
;; starting a new chain
(lc-loop (rest tail)
1 (list (first tail))
longest-length longest-chain)])))
For extra points: if there is more than one longest chain, which one does this function return? How could you change that so it makes the other choice? Or even a random choice!
Note the above version of the function uses named let, which is a standard construct in Scheme. If you don't want to use that you can just turn it into an explicit function:
(define (longest-chain l)
(define (lc-loop tail
current-length current-chain
longest-length longest-chain)
(cond [(null? tail)
;; we're done: return the longest chain
longest-chain]
[(and (not (null? current-chain))
(eqv? (first tail) (first current-chain)))
;; building on a current chain
(let ([chain (cons (first tail) current-chain)]
[chain-length (+ 1 current-length)])
(if (> chain-length longest-length)
;; the current chain is now the longest
(lc-loop (rest tail)
chain-length chain
chain-length chain)
;; it's not the longest yet
(lc-loop (rest tail)
chain-length chain
longest-length longest-chain)))]
[else
;; starting a new chain
(lc-loop (rest tail)
1 (list (first tail))
longest-length longest-chain)]))
(lc-loop l 0 '() 0 '()))
This is entirely equivalent to the above version. If you're not happy with internal defines, then you can turn lc-loop into a top-level definition.

Related

Implementing last-non-zero without continuations

last-non-zero takes a list of numbers and return the last cdr whose car is 0.
So, I can implement it using continuations, but how do I do this with natural recursion.
(define last-non-zero
(lambda (ls)
(let/cc return
(letrec
((lnz
(lambda (ls)
(cond
((null? ls) '())
((zero? (car ls)) ;; jump out when we get to last 0.
(return (lnz (cdr ls))))
(else
(cons (car ls) (lnz (cdr ls))))))))
(lnz ls)))))
Here's an obvious version which is not tail-recursive:
(define (last-non-zero l)
;; Return the last cdr of l which does not contain zero
;; or #f if there is none
(cond
((null? l)
#f)
((zero? (car l))
(let ((lnzc (last-non-zero (cdr l))))
;; This is (or lnzc (cdr l)) but that makes me feel bad
(if lnzc
lnzc
(cdr l))))
(else
(last-non-zero (cdr l)))))
Here is that version turned into a tail-recursive equivalent with also the zero test moved around a bit.
(define (last-non-zero l)
(let lnzl ([lt l]
[r #f])
(if (null? lt)
r
(lnzl (cdr lt) (if (zero? (car lt)) (cdr lt) r)))))
It's much clearer in this last version that the list is traversed exactly once.
Please indicate if I have correctly understood the problem:
#lang scheme
; returns cdr after last zero in lst
(define (last-non-zero lst)
; a helper function with 'saved' holding progress
(define (lnz-iter lst saved)
(if (null? lst)
saved
(if (zero? (car lst))
(lnz-iter (cdr lst) (cdr lst))
(lnz-iter (cdr lst) saved))))
(lnz-iter lst '()))
(last-non-zero '(1 2 3 0 7 9)) ; result (7 9)
Racket's takef-right can do it:
> (takef-right '(1 2 0 3 4 0 5 6 7) (lambda (n) (not (zero? n))))
'(5 6 7)
But assuming you have an assignment where you're supposed to write the logic yourself instead of just using a built in function, one easy if not very efficient approach is to reverse the list, build a new list out of everything up to the first zero, and return that. Something like:
(define (last-non-zero ls)
(let loop ([res '()]
[ls (reverse ls)])
(if (or (null? ls) (zero? (car ls)))
res
(loop (cons (car ls) res) (cdr ls)))))
Using your implementation where you return the argument in the event there are no zero you can just have a variable to keep the value you think has no zero values until you hit it and then update both:
(define (last-non-zero lst)
(let loop ((lst lst) (result lst))
(cond ((null? lst) result)
((zero? (car lst)) (loop (cdr lst) (cdr lst)))
(else (loop (cdr lst) result)))))
(last-non-zero '()) ; ==> ()
(last-non-zero '(2 3)) ; ==> (2 3)
(last-non-zero '(2 3 0)) ; ==> ()
(last-non-zero '(2 3 0 1 2)) ; ==> (1 2)
(define last-non-zero
(lambda (l)
((lambda (s) (s s l (lambda (x) x)))
(lambda (s l* ret)
(if (null? l*)
(ret '())
(let ((a (car l*))
(r (cdr l*)))
(if (zero? a)
(s s r (lambda (x) x))
(s s r
(lambda (r)
(ret (cons a r)))))))))))
Also possible, to use foldr:
(define (last-non-zero l)
(reverse (foldl (lambda (e res) (if (zero? e) '() (cons e res))) 0 l)))
Or use recursion:
(define (last-non-zero l (res '()))
(cond ((empty? l) res)
((zero? (car l)) (last-non-zero (cdr l) (cdr l)))
(else (last-non-zero (cdr l) res))))

How would I write a function in Racket which produces true if all the numbers in a list are the same and false otherwise?

How would I define a function in Dr. Racket which produces boolean true if all the numbers in a list are the same and false otherwise.
This is my code so far:
(define (same-numbers? lst)
(cond
[(empty? (rest lst)) (first lst)]
[else (equal? (first lst)(same-numbers? (rest lst)))]))
If I type in:
(same-numbers? (cons 5 (cons 5 (cons 5 empty))))
My desired output is true. However, instead, I get a false. How would I correct this?
As the comments point out, assuming the list contains only numbers the simplest approach is to do (apply = lst). If you want to implement this from scratch with explicit recursion, I suggest a different approach: if the list has more than one element, take the first element as reference and compare all the others against it, like this:
(define (same-numbers? lst)
(if (or (empty? lst) (empty? (rest lst))) ; trivial cases
#t
(let loop ((val (first lst)) ; take first element as reference
(lst (rest lst))) ; loop over the other elements
(or (empty? lst) ; base case: we're finished
(and (equal? (first lst) val) ; base case: stop if elements are different
(loop val (rest lst))))))) ; recursive case: keep iterating
It works for my test cases:
(same-numbers? '())
=> #t
(same-numbers? '(5))
=> #t
(same-numbers? '(5 5))
=> #t
(same-numbers? '(5 5 5))
=> #t
(same-numbers? '(5 1))
=> #f
(same-numbers? '(1 5))
=> #f
(same-numbers? '(1 5 5))
=> #f
(same-numbers? '(5 5 1))
=> #f
I'll start with your code so far, and find the problems with it:
(define (same-numbers? lst)
(cond
[(empty? (rest lst)) (first lst)]
[else (equal? (first lst)(same-numbers? (rest lst)))]))
The first problem I see is with the base case: if lst is a list of numbers then (first lst) will be a number, not a boolean like you wanted.
;; same-numbers? : [Listof Number] -> Boolean
To fix this, the base case should return #true:
(define (same-numbers? lst)
(cond
[(empty? (rest lst)) #true]
[else (equal? (first lst) (same-numbers? (rest lst)))]))
The next problem I see is with the recursive case: since same-numbers? returns a boolean, you shouldn't use equal? as if you're expecting a number. Instead use equal? between the first and the second:
(define (same-numbers? lst)
(cond
[(empty? (rest lst)) #true]
[else ... (equal? (first lst) (second lst)) ... (same-numbers? (rest lst)) ...]))
Now the ...s around that need to be filled with stuff that combines the information in "first two equal" and "rest same-numbers". They're all equal when the first two are equal AND the rest are the same, so fill in the ...s with and to combine them:
(define (same-numbers? lst)
(cond
[(empty? (rest lst)) #true]
[else (and (equal? (first lst) (second lst)) (same-numbers? (rest lst)))]))
If I type in:
> (same-numbers? (cons 5 (cons 5 (cons 5 empty))))
#true
There's still one problem left: the empty list. So just add another cond case for it:
;; same-numbers? : [Listof Number] -> Boolean
(define (same-numbers? lst)
(cond
[(empty? lst) #true]
[(empty? (rest lst)) #true]
[else (and (equal? (first lst) (second lst)) (same-numbers? (rest lst)))]))
Using it:
> (same-numbers? empty)
#true
> (same-numbers? (cons 5 empty))
#true
> (same-numbers? (cons 5 (cons 5 (cons 5 empty))))
#true
> (same-numbers? (cons 5 (cons 5 (cons 6 empty))))
#false
Just like Atharva Shukla's comment (apply = lst) is good.
But (apply = '()) will show error.
#lang Racket
(define lon (list 1/2 1/2 1/2 1/3))
(define lon2 (list 1/2 1/2 1/2 0.5))
(define (same-n? lon)
(andmap (lambda (n) (= (first lon) n)) lon))
;;; TEST
(same-n? lon) ; #f
(same-n? lon2) ; #t
(same-n? '()) ; #t

Returning newly created list with 1 element inside function

I'm currently working on building a function that returns a row of Pascal's triangle. My function passes in a list that contains a row in Pascal's triangle and returns the next row depending on which row was passed in.
ex. pass in '(1 2 1) and it should return '(1 3 3 1).
However I cannot seem to get the beginning 1 in the list.
(define build-next
(lambda(thisRow)
(cond
[(null? thisRow) '(1)]
[(null? (cdr thisRow)) (cons 1 (cdr thisRow))]
[else (cons (+ (car thisRow) (car (cdr thisRow))) (build-next(cdr thisRow)))])))
(build-next '(1 2 1))
Running this code will give me the output
'(3 3 1)
without the leading 1
Your functions works if the input row has a zero as first element.
Renaming your original function to build-next-helper and introducing
a new build-next that simply calls your existing function after prefixing a zero works fine:
(define build-next-helper
(lambda (thisRow)
(cond
[(null? thisRow) '(1)]
[(null? (cdr thisRow)) (cons 1 (cdr thisRow))]
[else (cons (+ (car thisRow) (car (cdr thisRow)))
(build-next-helper (cdr thisRow)))])))
(define (build-next thisRow)
(build-next-helper (cons 0 thisRow)))
(build-next '(1 2 1))
You can also use a named let to write build-next as follows:
(define (build-next row)
(let loop ([row row]
[acc 0])
(cond
[(zero? acc)
(cons 1 (loop row (add1 acc)))]
[(null? row) empty]
[(null? (cdr row)) (list 1)]
[else
(cons (+ (car row) (cadr row))
(loop (cdr row) acc))])))
The loop parameter acc is used as an accumulator to add the leading 1 in the next row (ie. first cond case).
For example,
(build-next '()) ;;=> '(1)
(build-next '(1)) ;;=> '(1 1)
(build-next '(1 1)) ;;=> '(1 2 1)
(build-next '(1 2 1)) ;;=> '(1 3 3 1)
(build-next '(1 3 3 1)) ;;=> '(1 4 6 4 1)
(build-next '(1 4 6 4 1)) ;;=> '(1 5 10 10 5 1)
Here is a possible solution:
(define build-next
(lambda(thisRow)
(define helper-build-next
(lambda (lst prev)
(if (null? lst)
(list prev)
(cons (+ prev (car lst)) (helper-build-next (cdr lst) (car lst))))))
(if (null? thisRow)
(list 1)
(cons (car thisRow) (helper-build-next (cdr thisRow) (car thisRow))))))
The recursion is performed through a helper function, that gets the rest of the row and the previous element of the row. Initially the function checks if the parameter is the empty list, so that the first row of the triangle is returned. Otherwise, the helper function is called with the initial parameters.

How to remove the last element in a list using scheme

I have a requirement to return the last negative number in a list, using a recursive procedure. Right now I have a recursive procedure that returns all negative numbers in the list.
(define returnLastNeg
(lambda (lst)
(if (null? lst)
'()
(if (positive? (car lst))
(returnLastNeg (cdr lst))
(cons (car lst) (returnLastNeg (cdr lst)))))))
calling it with (returnLastNeg'(1 -2 -3 4 -5 6)) returns
Output:
'(-2 -3 -5)
I need it to only return -5 though. I tried to modify my procedure to check to see if the last element in the list is positive. If it is, I want to remove the last element and then call the procedure again. But when I do that I get an error (below)
Modified procedure:
(define returnLastNeg-modified
(lambda (lst)
(if (null? lst)
'()
(if (positive? (last lst))
(remove (last lst) (lst))
(cons (car lst) (returnLastNeg-modified (cdr lst)))))))
ERROR:
application: not a procedure;
expected a procedure that can be applied to arguments
given: '(1 -2 -3 4 -5 6)
arguments...: [none]
>
A simpler approach would be with a helper procedure (called "sub") in this example:
(define returnLastNeg
(lambda (lst)
(define sub
(lambda (lst last-neg)
(if (null? lst)
last-neg
(let ((c (car lst)))
(sub (cdr lst)
(if (negative? c) c last-neg))))))
(sub lst null)))
EDIT
Knowing that
(define <procedureName> (lambda (<params>) ... )
is the same as
(define (<procedureName> <params>) ... )
and reformatting a little, this becomes:
(define (returnLastNeg lst)
(define (sub lst last-neg)
(if (null? lst)
last-neg
(let ((c (car lst)))
(sub (cdr lst) (if (negative? c) c last-neg)))))
(sub lst null))
I hope it's clearer
last-neg gets set to null by the very last expression
the recursive call to sub has 2 parameters (split on 2 lines in the initial version, but newlines don't matter).
This is the same as the even shorter version
(define (returnLastNeg lst)
(let sub ((lst lst) (last-neg null))
(if (null? lst)
last-neg
(let ((c (car lst)))
(sub (cdr lst) (if (negative? c) c last-neg))))))
using a so-called "named let".

Scheme sum of list

First off, this is homework, but I am simply looking for a hint or pseudocode on how to do this.
I need to sum all the items in the list, using recursion. However, it needs to return the empty set if it encounters something in the list that is not a number. Here is my attempt:
(DEFINE sum-list
(LAMBDA (lst)
(IF (OR (NULL? lst) (NOT (NUMBER? (CAR lst))))
'()
(+
(CAR lst)
(sum-list (CDR lst))
)
)
)
)
This fails because it can't add the empty set to something else. Normally I would just return 0 if its not a number and keep processing the list.
I suggest you use and return an accumulator for storing the sum; if you find a non-number while traversing the list you can return the empty list immediately, otherwise the recursion continues until the list is exhausted.
Something along these lines (fill in the blanks!):
(define sum-list
(lambda (lst acc)
(cond ((null? lst) ???)
((not (number? (car lst))) ???)
(else (sum-list (cdr lst) ???)))))
(sum-list '(1 2 3 4 5) 0)
> 15
(sum-list '(1 2 x 4 5) 0)
> ()
I'd go for this:
(define (mysum lst)
(let loop ((lst lst) (accum 0))
(cond
((empty? lst) accum)
((not (number? (car lst))) '())
(else (loop (cdr lst) (+ accum (car lst)))))))
Your issue is that you need to use cond, not if - there are three possible branches that you need to consider. The first is if you run into a non-number, the second is when you run into the end of the list, and the third is when you need to recurse to the next element of the list. The first issue is that you are combining the non-number case and the empty-list case, which need to return different values. The recursive case is mostly correct, but you will have to check the return value, since the recursive call can return an empty list.
Because I'm not smart enough to figure out how to do this in one function, let's be painfully explicit:
#lang racket
; This checks the entire list for numericness
(define is-numeric-list?
(lambda (lst)
(cond
((null? lst) true)
((not (number? (car lst))) false)
(else (is-numeric-list? (cdr lst))))))
; This naively sums the list, and will fail if there are problems
(define sum-list-naive
(lambda (lst)
(cond
((null? lst) 0)
(else (+ (car lst) (sum-list-naive (cdr lst)))))))
; This is a smarter sum-list that first checks numericness, and then
; calls the naive version. Note that this is inefficient, because the
; entire list is traversed twice: once for the check, and a second time
; for the sum. Oscar's accumulator version is better!
(define sum-list
(lambda (lst)
(cond
((is-numeric-list? lst) (sum-list-naive lst))
(else '()))))
(is-numeric-list? '(1 2 3 4 5))
(is-numeric-list? '(1 2 x 4 5))
(sum-list '(1 2 3 4 5))
(sum-list '(1 2 x 4 5))
Output:
Welcome to DrRacket, version 5.2 [3m].
Language: racket; memory limit: 128 MB.
#t
#f
15
'()
>
I suspect your homework is expecting something more academic though.
Try making a "is-any-nonnumeric" function (using recursion); then you just (or (is-any-numeric list) (sum list)) tomfoolery.

Resources