Count-Syllables function scheme - scheme

I want to Implement the procedure count-syllables which takes a list of letters as its argument and returns the number of syllables in the word formed by the letters, according to the following rule:
The number of syllables is the number of vowels, except that a group of consecutive vowels counts as one. Vowels are the letters:
(define vowels '(a e i o u))
example:
(count-syllables '(s o a r i n g)) ; output = 2 ('oa' and 'i')
(count-syllables '(b e e p)) ; output = 1 ('ee')
I have writen this code :
(define count-syllables
(lambda (l)
(if (empty? l)
0
(if (memq (car l) '(a e i o u)) ; if we found a match
(+ 1 (count-syllables (cdr l)))
(count-syllables (cdr l))))))
but this code doesnt count consecutive vowels as one when typing '(s o a r i n g)
it outputs 3 and when typing '(b e e p) it outputs 2

You need to account for the consecutive vowels instead of adding 1 everytime you find a vowel. Here is an example of how you can handle such a case using mutual recursion:
(define (count-syllables lst)
(cond
((null? lst) 0)
((member (car lst) '(a e i o u))
(+ 1 (skip-vowels (cdr lst))))
(else
(count-syllables (cdr lst)))))
(define (skip-vowels lst)
(cond
((null? lst)
(count-syllables '()))
((member (car lst) '(a e i o u))
(skip-vowels (cdr lst)))
(else
(count-syllables lst))))
Essentially, everytime you find a vowel in the list, you add 1, then send that list to skip-vowels, which then removes the next consecutive vowels and sends the list back to count-syllables.
Then you can have:
(count-syllables '(s o a r i n g))
=> 2
(count-syllables '(b e e p))
=> 1

Related

Trying to replace all instances of an element in a list with a new element [Racket]

As the title said, I'm trying to write a function that takes a list, a variable, and an element, then replaces all instances of the variable in the list with that element.
For example:
(substitute '(C or (D or D)) 'D #f) would return
'(C or (#f or #f))
Right now what I've got is:
(define (substitute lst rep new)
(cond ((or (null? lst))
lst)
((eq? (car lst) rep)
(cons new (substitute (cdr lst) rep new)))
(else
(cons (car lst) (substitute (cdr lst) rep new)))))
Which doesn't check nested lists like my example, though it works fine when they aren't a part of the input.
And I'm having trouble with where to place recursion in order to do so - or would it be easier to flatten it all and then rebuild it after everything's been replaced in some way?
Here's another solution using pattern matching via match -
(define (sub l rep new)
(match l
((list (list a ...) b ...) ; nested list
(cons (sub a rep new)
(sub b rep new)))
((list a b ...) ; flat list
(cons (if (eq? a rep) new a)
(sub b rep new)))
(_ ; otherwise
null)))
It works like this -
(sub '(a b c a b c a b c) 'a 'z)
;; '(z b c z b c z b c)
(sub '(a b c (a b c (a b c))) 'a 'z)
;; '(z b c (z b c (z b c)))
(sub '() 'a 'z)
; '()
At first sight, your question looks similar to How to replace an item by another in a list in DrScheme when given paramters are two items and a list?. From my understanding, your question is slightly different because you also want to replace occurrences within nested lists.
In order to deal with nested lists, you must add a clause to check for the existence of a nested list, and replace all occurrences in that nested list by recursing down the nested list:
(define (subst l rep new)
(cond ((null? l)
'())
((list? (car l)) ; Check if it is a nested list.
(cons (subst (car l) rep new) ; Replace occurrences in the nested list.
(subst (cdr l) rep new))) ; Replace occurrences in the rest of the list.
((eq? (car l) rep)
(cons new
(subst (cdr l) rep new)))
(else
(cons (car l)
(subst (cdr l) rep new)))))
Example use (borrowed from the answer given by user633183):
(subst '(a b c a b c a b c) 'a 'z)
;; '(z b c z b c z b c)
(subst '(a b c (a b c (a b c))) 'a 'z)
;; '(z b c (z b c (z b c)))
(subst '() 'a 'z)
; '()
This can be done using map and recursion:
(define (subst lst rep new)
(map (lambda (x)
(if (list? x)
(subst x rep new)
(if (eq? rep x) new x))) lst))
the output:
(subst '(a b c (a b c (a b c))) 'a 'z)
; '(z b c (z b c (z b c)))

Scheme: using backtracking to find sentence permutations given chars list and words list

Given chars - a list of characters and words - and list of words. I wish to find all possible permutations of sentences from given words list that use all chars.
For example:
chars = '(i l o v e t e l e v i s i o n)
words = '((i) (l o v e) (v i s i o n) (t e l e) (t e l e v i s i o n))
So running (find-permutations '(i l o v e t e l e v i s i o n) '((i) (l o v e) (v i s i o n) (t e l e) (t e l e v i s i o n))) will yield the following result:
(((i) (l o v e) (t e l e) (v i s i o n))
((i) (l o v e) (t e l e v i s i o n)))
I wrote the following code using Scheme language:
(define (substr sub str)
(cond ((null? sub) str)
((null? str) #f)
((eq? (car sub) (car str)) (substr (cdr sub) (cdr str)))
(else #f)))
(define (find-permutations chars words)
(define (helper chars words1 result)
(cond ((null? chars) (reverse result))
((null? words1) null)
((eq? chars #f) #f)
(else (let* (
(x (substr (car words1) chars))
(y (helper x words (cons (car words1) result)))
(w (helper chars (cdr words1) result))
)
(if x
(cons y w)
w)
)
)
)
)
(trace helper)
(helper chars words ())
)
but i got too many brackets:
((((((i) (l o v e) (t e l e) (v i s i o n))) ((i) (l o v e) (t e l e v i s i o n)))))
I can't find why. Can anyone have an idea?
You should use append rather than cons
(define (substr? sub str)
(cond ((null? sub) str)
((null? str) #f)
((eq? (car sub) (car str)) (substr? (cdr sub) (cdr str)))
(else #f)))
(define (find-permutations chars words)
(define (helper chars words1 result)
(cond ((null? chars) (reverse result))
((null? words1) #nil)
((eq? chars #f) #f)
(else (let* ((chars-substr? (substr?
(car words1) chars))
(head (helper chars-substr? words (cons (car words1) result)))
(tails (helper chars (cdr words1) result)))
(if chars-substr?
(append head tails)
tails)))))
(helper chars words '()))
When you cons together two lists as you did in your final predicate (cons x y), you are creating a "nested" structure by assigning your new results to a deeper and deeper chain of car pointers.
You might not notice this subtle difference because convention dictates omitting the 'true' structure of an S-expression list because the car cell is where associated list data is typically held.
The following diagram shows the list (1 . (2 . (3 . (4 . ()), which would be printed as (1 2 3 4) because of this convention.
Conversely, when car holds another list (rather than a value like 1), it frequently represents a hierarchical structure, which is formatted with multiple enclosing parenthesis.

Getting every nth atom using scheme does not pick up the last atom

The program is suppose to pick out every third atom in a list.
Notice that the last atom 'p' should be picked up, but its not.
Any suggestions as to why the last atom is not being selected.
(define (every3rd lst)
(if (or (null? lst)
(null? (cdr lst)))
'()
(cons (car lst)
(every3rd (cdr(cdr(cdr lst)))))))
(every3rd '(a b c d e f g h i j k l m n o p))
Value 1: (a d g j m)
Thanks
You're missing a couple of base cases:
(define (every3rd lst)
(cond ((or (null? lst) (null? (cdr lst))) lst)
((null? (cdr (cdr lst))) (list (car lst)))
(else (cons (car lst)
(every3rd (cdr (cdr (cdr lst))))))))
See how the following cases should be handled:
(every3rd '())
=> '()
(every3rd '(a))
=> '(a)
(every3rd '(a b))
=> '(a)
(every3rd '(a b c))
=> '(a)
(every3rd '(a b c d))
=> '(a d)
(every3rd '(a b c d e f g h i j k l m n o p))
=> '(a d g j m p)
Fixing your code (covering the base cases)
It's worth noting that Scheme defines a number of c[ad]+r functions, so you can use (cdddr list) instead of (cdr (cdr (cdr list))):
(cdddr '(a b c d e f g h i))
;=> (d e f g h i)
Your code, as others have already pointed out, has the problem that it doesn't consider all of the base cases. As I see it, you have two base cases, and the second has two sub-cases:
if the list is empty, there are no elements to take at all, so you can only return the empty list.
if the list is non-empty, then there's at least one element to take, and you need to take it. However, when you recurse, there are two possibilies:
there are enough elements (three or more) and you can take the cdddr of the list; or
there are not enough elements, and the element that you took should be the last.
If you assume that <???> can somehow handle both of the subcases, then you can have this general structure:
(define (every3rd list)
(if (null? list)
'()
(cons (car list) <???>)))
Since you already know how to handle the empty list case, I think that a useful approach here is to blur the distinction between the two subcases, and simply say: "recurse on x where x is the cdddr of the list if it has one, and the empty list if it doesn't." It's easy enough to write a function maybe-cdddr that returns "the cdddr of a list if it has one, and the empty list if it doesn't":
(define (maybe-cdddr list)
(if (or (null? list)
(null? (cdr list))
(null? (cddr list)))
'()
(cdddr list)))
> (maybe-cdddr '(a b c d))
(d)
> (maybe-cdddr '(a b c))
()
> (maybe-cdddr '(a b))
()
> (maybe-cdddr '(a))
()
> (maybe-cdddr '())
()
Now you can combine these to get:
(define (every3rd list)
(if (null? list)
'()
(cons (car list) (every3rd (maybe-cdddr list)))))
> (every3rd '(a b c d e f g h i j k l m n o p))
(a d g j m)
A more modular approach
It's often easier to solve the more general problem first. In this case, that's taking each nth element from a list:
(define (take-each-nth list n)
;; Iterate down the list, accumulating elements
;; anytime that i=0. In general, each
;; step decrements i by 1, but when i=0, i
;; is reset to n-1.
(let recur ((list list) (i 0))
(cond ((null? list) '())
((zero? i) (cons (car list) (recur (cdr list) (- n 1))))
(else (recur (cdr list) (- i 1))))))
> (take-each-nth '(a b c d e f g h i j k l m n o p) 2)
(a c e g i k m o)
> (take-each-nth '(a b c d e f g h i j k l m n o p) 5)
(a f k p)
Once you've done that, it's easy to define the more particular case:
(define (every3rd list)
(take-each-nth list 3))
> (every3rd '(a b c d e f g h i j k l m n o p))
(a d g j m)
This has the advantage that you can now more easily improve the general case and maintain the same interface every3rd without having to make any changes. For instance, the implementation of take-each-nth uses some stack space in the recursive, but non-tail call in the second case. By using an accumulator, we can built the result list in reverse order, and return it when we reach the end of the list:
(define (take-each-nth list n)
;; This loop is like the one above, but uses an accumulator
;; to make all the recursive calls in tail position. When
;; i=0, a new element is added to results, and i is reset to
;; n-1. If i≠0, then i is decremented and nothing is added
;; to the results. When the list is finally empty, the
;; results are returned in reverse order.
(let recur ((list list) (i 0) (results '()))
(cond ((null? list) (reverse results))
((zero? i) (recur (cdr list) (- n 1) (cons (car list) results)))
(else (recur (cdr list) (- i 1) results)))))
It is because (null? '()) is true. you can debug what's happening with following code
(define (every3rd lst)
(if (begin
(display lst)
(newline)
(or (null? lst)
(null? (cdr lst))))
'()
(cons (car lst)
(every3rd (cdr(cdr(cdr lst)))))))
(every3rd '(a b c d e f g h i j k l m n o p))
(newline)
(display (cdr '(p)))
(newline)
(display (null? '()))
(newline)
(display (null? (cdr '(p))))
(newline)
this gives following result.
(a b c d e f g h i j k l m n o p)
(d e f g h i j k l m n o p)
(g h i j k l m n o p)
(j k l m n o p)
(m n o p)
(p)
()
#t
#t

DR Racket Flip a list of letter

this is a recursive function flip in Scheme which accepts a list of atoms of arbitrary length as its only argument and returns that list with adjacent elements flipped. In other words, the
function alternates elements of a list (i.e., given a list [a1,a2,a3,a4,a5,a6...,an] as an argument,
produce [a2,a1,a4,a3,a6,a5,...]). If n is odd, an remains at the end of the resulting list. not using any auxiliary functions.
here is my sample
> (flip '())
()
> (flip '(a))
(a)
> (flip '(a b))
(b a)
> (flip '(a b c d))
(b a d c)
> (flip '(a b c d e))
(b a d c e)
This is homework, so I can't give you a straight answer. Here's the general idea of the solution, fill-in the blanks:
(define (flip lst)
(cond ((null? lst) ; The list is empty:
<???>) ; return the empty list.
((null? (cdr lst)) ; The list has a single element:
<???>) ; return a list with the single element.
(else ; The list has at least two elements:
(cons <???> ; cons the second element ...
(cons <???> ; ... to the first element ...
(flip <???>)))))) ; ... and advance two elements at once.
(define (flip lst)
(cond ((null? lst)
null)
((null? (cdr lst))
lst)
(else
(cons (car (cdr lst))
(cons (car lst)
(flip (cdr (cdr lst))))))))

Get last n elements in a list in DrRacket, without list-ref

I know how to get the first n elements in a list,
(define (countup n ls)
(cond
[(zero? n) '()]
[else (cons (first ls) (countup (sub1 n) (rest ls)))]))
but how can I do something like this for the last n elements in a list (without using list-ref)?
If I call (countup 3 '(a b c d e)), I get (list a b c). I need to be able to enter (counter 3 '(a b c d e)) and get (list c d e).
I need error messages in case the number n given is bigger than the list's length.
Just use the built-in take-right procedure, it does exactly what you need:
(take-right '(a b c d e) 3)
=> '(c d e)
Or you can implement it from scratch, using primitive procedures:
(define (counter n lst)
(define (move n lst)
(if (zero? n)
lst
(move (sub1 n) (rest lst))))
(define (trim-left lst rst)
(if (empty? rst)
lst
(trim-left (rest lst) (rest rst))))
(trim-left lst (move n lst)))
It also works as expected:
(counter 3 '(a b c d e))
=> '(c d e)
I guess I would use a local fn to chop of items from the left and then return the remaining items. The following also returns '() if asked to return a Negative number of items. You may want to treat this as an error as well. #f signals an error in your input ie trying to take more items than the list contains
(define (counter n loN)
(define (acc loN c)
(cond [(null? loN) '()]
[(> c 0) (acc (cdr loN) (sub1 c))]
[else loN]))
;in
(let ((c (- (length loN) n)))
(cond ; [(>= 0 n) #f]
[(positive? c) (acc loN c)]
[else #f])))
(check-equal? (counter 3 '(a b c d e)) '(c d e))
(check-equal? (counter 6 '(a b c d e)) #f)
(check-equal? (counter -3 '(a b c d e)) '())
(check-equal? (counter 0 '(a b c d e)) '())

Resources