About strings and substrings - scheme

How would you design a function that consumes a string and a number i which inserts "_" at the ith position of the string?
(define (string-insert n i)
(substring n i))
I just need to add the "_" at the ith position which is driving me crazy

Just use string-append and substring, the trick is to get the indexes right:
(define (string-insert n i)
(string-append
(substring n <???> <???>)
"_"
(substring n <???>)))
I'll let you figure out the details, you'll see that it works as expected:
(string-insert "HelloWorld" 5)
=> "Hello_World"

Related

How do I sort my string list with Recursion?

I'm trying to write code where it creates a string list increasing order with using only recursion and nothing else.
How should I go about doing this?
(define (create-list n st)
(cond [(zero? n) ""]
[else (string-append "X" (create-list (sub1 n) st))]))
(define (stair n)
(cond [(equal? n 0) empty]
[else (cons (create-list n "x") (stair (- n 1)))]))
;; (stair 4) --> (list "XXXX" "XXX" "XX" "X")
Desired output: (list "X" "XX" "XXX" "XXXX")
Replace
(cons (create-list n "x") (stair (- n 1)))
with
(append (stair (- n 1)) (list (create-list n "Q")))
(Note that create-list doesn't actually use the st argument.)
All Scheme lists are created from end to beginning. You want to create ("XXXX") first, then ("XXX" "XXXX") etc. Whenever you do (cons "X" (recursion ....)) then (recursion ...) needs to finish before the cons while the most efficient is by using an accumulator. Using append each step smell wrong since append is O(n) so if you do do that each step then you have O(n^2). With a couple of thousand elements you'll start noticing the difference.
You don't need create-list, which doesn't create a list but a string, since Scheme has make-string that does what you want:
(make-string 3 #\X) ; ==> "XXX"
So here is stair:
(define (stair n)
(define (xs n)
(make-string n #\X))
(let helper ((n n) (acc '()))
(if (zero? n)
acc
(helper (- n 1)
(cons (xs n) acc)))))
So in this case if you wanted it in the reverse order you would have used different name than n and gone upward until this and n were passed. Sometimes you don't have the luxury to choose, eg, if you were to copy a list, then often you can building the reverse, then reverse the result. Sometime you need to use memory and need the continuations, but this will restrict how deep your structures can be before the program stops working. In rackets case it doesn't stop until you have depleted the whole heap memory you have supplied it.

In beginner scheme how do I represent a variable as a string?

My question is how do i code for
(triangle 5) produces (list "*****" "****" "***" "**" "*")
Note: (5 astericks 4, then 3 then 2 then 1). So far I have:
(define (triangle n)
(cond
[(zero? n) empty]
[else (cons n (triangle (sub1 n)))]))
But that only gives me (list 5 4 3 2 1). Please keep note that this uses only the basic of scheme beginner lists and abbreviations. Thanks!
It's always a good idea to split a complex problem in simpler, shorter subparts. In this case, we can simplify the general solution by first writing solutions to subproblems, like this:
First, build a procedure that creates a list of strings, where a string is "*****" or "****" or ... or "*"
Second, write a repeat helper procedure that given a string and a number, repeats the string that many times - for example: (repeat "*" 3) will return "***"
It's easy to see how the first subproblem can be expressed in terms of the second one. Because this looks like a homework, you shouldn't be asking for complete solutions here. It'll be more useful for you to reach the answer by yourself, here's the general idea, fill-in the blanks:
(define (triangle n)
(cond [<???> <???>] ; if n is zero return the empty list: '()
[else ; otherwise
(cons <???> ; cons n repetitions of * (using `repeat`)
(triangle <???>))])) ; and advance the recursion
(define (repeat str n)
(cond [<???> <???>] ; if n is zero return the empty string: ""
[else ; otherwise
(string-append <???> ; append the given string
(repeat <???> <???>))])) ; and advance the recursion
If you look at it carefully, both procedures share exactly the same structure. What changes is the value returned in the base case (an empty list and an empty string) and the procedure used for sticking together the partial answers (cons and string-append).
If you're just looking for how to convert numbers to string, you can use the (number->string x).
However, since you're looking to have the numbers represented as asterisks, it may be better for you to keep them as numbers until you've constructed a string of asterisks. In that case, you probably want a method like:
(define (num-to-asterisks x)
(make-string x #\*))
Try this:
(define (triangle n)
(let building ((i 0) (r '()))
(if (= i n)
r
(building (+ i 1)
(cons (string-append "*" (if (null? r) "" (car r)))
r)))))
this is nicely tail-recursive; builds up the result list by adding "*" to the first element of the result list.

(Scheme) Find distance between two words in a list?

Ok, so I'm trying to write a function that finds the distance between two elements in a list, s and t.
For example, if s = bob and t = pizza:
(d 'bob 'pizza '(bob blah blah pizza))
it would return: 3
This is what I have so far.
(define dist
(lambda (s t line)
(cond
[(equal? s (car line))
[(equal? t (car (cdr line)))
1]]
[else (add1 (dist s t (cdr line)))])))
For some reason, it's not working. Help?
Thanks!
The proposed code in the question is not going to work, it's just checking if the two elements are contiguous in the list. Let's try a different approach altogether - split the problem in smaller subproblems, begin by defining a procedure that returns the index of an element in a list, counting indexes from zero:
(define (index-of elt lst)
<???>) ; ToDo
With the above procedure in place, and assuming that both s and t are present in the list and t appears after s, it's easy to find the solution to the question:
(define dist
(lambda (s t line)
(- (index-of t line)
(index-of s line))))
For example:
(dist 'bob 'pizza '(bob blah blah pizza))
=> 3
For extra credit, consider the cases where one or both of the elements are not present in the list (so index-of should return a value indicating this, say, #f), or when s appears after t in the list.
When you are taking (cdr line) in the last step you are throwing away bob even if bob is the first element.
You need to take care of 3 and maybe 4 cases.
Where s and t match the first two elements you do fine.
Where s matches and t doesn't you need to add 1 to a recursive call using line with the 2nd element removed. Something like (cons (car line) (cdr (cdr line))).
Where s doesn't match you need to remove the car of line and try again.
Unless you are sure s and t will both occur and in order you need a terminating condition(s) to take care of running out of line.
Here is a solution that iterates down the list looking for 's' and 't' each time. When both have been seen, the result is returned; otherwise, continue looking:
(define (dist s t line)
(let looking ((l line) (n 0) (i #f))
(and (not (null? l))
(let ((item (car l)))
(if (or (equal? item s)
(equal? item t))
(if (not i)
(looking (cdr l) (+ n 1) n) ; found first, continue
(- n i)) ; found second, done
(looking (cdr l) (+ n 1) i)))))); continue looking

Building repeating strings with spaces between the repeats

repeat takes in a number and a string, and returns the string repeated n times, separated by a space.
;; repeat: number string -> string
(define (repeat n str)
(replicate n str))
(repeat 2 "home")
gives me:
"homehome"
How would I add a space so it can give me "home home"?
Add a space to the string str at the end, before passing it to replicate:
(replicate n (string-append str " "))
That'll leave an extra space at the end, if you want to get rid of it do as #Tobia suggests:
(string-trim (replicate n (string-append str " ")))
Racket has a build-in function string-join for this, so in plain Racket this would be
> (string-join (build-list 2 (lambda (i) "home")))
"home home"

Anagrams in scheme

Has anyone tried generating anagrams in scheme???
I have a list ( A B C D E F) and need to create anagrams of length 4. Like 'AAAA','ABCD','BCBC' etc.
I am totally confused. :(
Could someone please give me an heads-up on how I could go about it??
Hmm... Recently I solved very similar task - create anagrams of length N from (0 1). Here is my solution. May be it helps you:
;;
;; (define (generate n)) -> create list of string where
;; * length of each string is n
;; * each symbol of string is '0' or '1'
;; * the list has all possible combinations of symbols '0' and '1'
(define (generate n)
(generate-engine (list "0" "1") n))
(define (generate-engine lst n)
(cond
[(= n 1) lst]
[else (generate-engine (append (add-to-list lst "0") (add-to-list lst "1")) (- n 1))])
)
(define (add-to-list lst symbol)
(cond
[(empty? lst) empty]
[else (cons (add-to-element (first lst) symbol) (add-to-list (rest lst) symbol))]))
(define (add-to-element element symbol)
(string-append element symbol)
)
;; example
(generate 3)
Result:
(list "000" "100" "010" "110" "001" "101" "011" "111")
For each i = 0..x where x is the length of the anagram, generate a random number r such that 0 <= r <= n where n is the number of elements in the list of letters. Now use r as an index into the list of letters and concatenate it to the result.
Base case
Anagrams of length 1 are just the items in the list. Return the list.
Recursive case
Anagrams of length n are each of the items in the list appended to all of the anagrams of length (- n 1).
From that you ought to be able to cook up some example of the base case and recursive case. You'll probably need a helper function.

Resources