The goal of the code is that. after i add a new item, i need to add a new quantity to the product i want and by using set!, i need that the new quantity really change.
(define-struct articulo (nombre cantidadDisponible))
(define listaArticulos empty)
(define (productoNuevo nom can)
(set! listaArticulos
(cons (make-articulo nom can) listaArticulos)))
(define (agregarValor datoABuscar datoASumar)
(local
(
(define (agregar lista buscar valorSumar)
(cond
[(empty? lista)empty]
[(string=? buscar (articulo-nombre (car listaArticulos)))
(make-articulo (+ (articulo-cantidadDisponible(car lista)) valorSumar)
(agregar (cdr lista)buscar valorSumar))]
[else (make-articulo (car lista) (agregar (cdr lista) buscar valorSumar))]
)
)
)
(begin
(set! listaArticulos (agregar listaArticulos datoABuscar datoASumar))
)
)
)
Adding new items to the itemlist
(productoNuevo "tomatoes" 20)
(productoNuevo "oranges" 20)
Then i need to add a new quantity to the product i want
(agregarValor "tomatoes" 10)
Then i want to confirm that the new quantity was added
listaArticulos
The output must be
(list (make-articulo "oranges" 20) (make-articulo "tomatoes" 30))
But is instead
(make-articulo 30 (make-articulo 30 '()))
Can you please help me with this?
I'm afraid the procedure's logic isn't right. These are the main issues:
You need to build a new list as the output, and only after that, set! the result to the external list.
Both the second and third conditions need to be rewritten so they construct the output list with cons.
The line with the string=? condition is incorrect, you're taking the car of the wrong list.
When calling make-articulo, you forgot to pass the the name of the item.
This should fix the problems:
(define (agregarValor datoABuscar datoASumar)
(local
((define (agregar lista buscar valorSumar)
(cond
[(empty? lista) empty]
[(string=? buscar (articulo-nombre (car lista)))
(cons
(make-articulo (articulo-nombre (car lista))
(+ (articulo-cantidadDisponible (car lista)) valorSumar))
(agregar (cdr lista) buscar valorSumar))]
[else (cons (car lista) (agregar (cdr lista) buscar valorSumar))])))
(begin
(set! listaArticulos (agregar listaArticulos datoABuscar datoASumar)))))
Now it works as expected:
(define (print lst)
(for-each (λ (articulo)
(printf "~s: ~s ~n"
(articulo-nombre articulo)
(articulo-cantidadDisponible articulo)))
lst))
(productoNuevo "tomatoes" 20)
(productoNuevo "oranges" 20)
(print listaArticulos)
=> "oranges": 20
"tomatoes": 20
(agregarValor "tomatoes" 10)
(print listaArticulos)
=> "oranges": 20
"tomatoes": 30
Related
Here is the question I am trying to solve
Write a function (last-substring-len s n).
It consumes a Str and a Nat, and returns the substring of s with
length n that comes last alphabetically.
Remember to consider if your function Requires anything of its
arguments!
For example:
(last-substring-len "foobar" 4) => "ooba"
(last-substring-len "thequickbrownfoxjumpsoverthelazydogs" 7) => "xjumpso"
I have actually nearly solved my question but I want to be able to instead alter my code so that the if statements for the function get-maximium are replaced with cond statements.
This is my original code:
(define (substrings-w-len s n)
(cond
[(> n (string-length s)) '()]
[ else (cons (substring s 0 n)
(substrings-w-len (substring s 1 (string-length s)) n))]))
(define (get-maximium string-list)
(if(null? string-list) '()
(if(= 1( length string-list)) string-list
(if (equal? #true (string>=? (first string-list) (first (rest string-list))))
(get-maximium (cons (first string-list) (rest (rest string-list))))
(get-maximium (rest string-list))))))
(define (last-substring-w-len s n)
( get-maximium (substrings-w-len s n)))
(check-expect (last-substring-w-len "foobar" 4) "ooba")
This yields (list "ooba") when it should only yield "ooba" so I need to convert the list into a string which I should be able to solve myself but i'd appreciate if someone could help me with this.
The main issue now though is i want to replace the if statements in get-maximum with a conditional statement
This is me altering the get-maximium function to try to replace the if functions with a cond statement but it doesn't work yet.
(define (get-maximium string-list)
(cond
[(null? string-list) '()]
[(= 1( length string-list)) string-list]
[ else (equal? #true (string>=? (first string-list) (first (rest string list))))
(get-maximium (cons (first string-list) (rest (rest string-list))))
(get-maximium (rest string-list))]))
There's an issue with the else part. It should look like this:
(define (get-maximium string-list)
(cond [(null? string-list) '()]
[(= 1 (length string-list)) string-list]
[(string>=? (first string-list) (first (rest string list)))
(get-maximium (cons (first string-list) (rest (rest string-list))))]
[else (get-maximium (rest string-list))]))
Also, there's no need to ask (equal? #t <condition>), simply ask <condition>.
Try to retrieve the first element of the answer like so:
(define (last-substring-w-len s n)
(first ( get-maximium (substrings-w-len s n))))
(last-substring-w-len "foobar" 4) => "ooba"
(last-substring-w-len "thequickbrownfoxjumpsoverthelazydogs" 7) => "xjumpso"
For a thorough explanation see my answer here
Essentially, I just want to convert a string sentence into a list of individual string words using DrRacket/Scheme. I currently am using Intermediate Student with Lambda so that may limit some functions I can use but any assistance would be appreciated. For instance I want
(split-string "the man over there is close") to yield
(list "the" "man" "over" "there" "is" "close")
This problem is slightly tricky. For starters, you need to think about the input string as a list of chars. Every time a space is encountered, we know that a new word is complete.
We can keep track of the current word in a variable, and use an accumulator for storing whole words, being careful of reversing the intermediate values, because we'll be consing them so they'll be in reverse. This is what I mean:
(define (split-string lst)
(let loop ((acc '()) (current '()) (chars (string->list lst)))
(cond ((null? chars)
(reverse (cons (list->string (reverse current)) acc)))
((char=? (car chars) #\space)
(loop (cons (list->string (reverse current)) acc)
'()
(cdr chars)))
(else
(loop acc
(cons (car chars) current)
(cdr chars))))))
It works as expected:
(split-string "the man over there is close")
=> '("the" "man" "over" "there" "is" "close")
Tail call recursive version
For single character separators.
(define (split-string s (sep #\space))
(define (rec-split sl sep (acc '()) (h-acc '()))
(cond ((empty? sl) (reverse (map (lambda (isl) (list->string isl))
(cons (reverse h-acc) acc))))
((char=? (car sl) sep) (rec-split (cdr sl) sep (cons (reverse h-acc) acc) '()))
(else (rec-split (cdr sl) sep acc (cons (car sl) h-acc)))))
(rec-split (string->list s) sep))
> (split-string "the man over there is close")
;; '("the" "man" "over" "there" "is" "close")
I am trying to modify the cdr of the car of an element of a list using set!, but I am getting an error: "set! not an identifier". Can anyone explain to me why this is happening? I am starting to work with objects by the way.
#lang racket
(define (multiset)
(let ((main-list '()))
(define (empty)
(eq? main-list '()))
(define (insert x)
(cond ((empty)
(set! main-list (cons (cons x 1) main-list)))
((= (car (car main-list)) x)
(begin (set! (cdr (car main-list))
(+ 1 (cdr (car main-list))))))
(else (cdr main-list))))
A multiset is represented as a list of pairs. For example, if I had a list '(1 1 1 2 2 2), the multiset representation would be '((1.3)(2.3))
The syntax of set! is
(set! <identifier> <expression>)
which is to say that the first form must be a symbol. In your code you are using:
(cdr (car main-list))
as the 'identifier' - hence the error.
Perhaps your background is CommonLisp and you are expecting set! to behave like setf? In Scheme there are separate functions for setting the 'car' and 'cdr' of a pair. Use set-car! and set-cdr!
> (define pair (cons 'car 'cdr))
> pair
(car . cdr)
> (set-car! pair 'foo)
> pair
(foo . cdr)
> (set-cdr! pair 'bar)
> pair
(foo . bar)
In R6RS (and probably R7RS) set-car! and set-cdr! can be found in the (rnrs mutable-pairs) library
GoZoner has given you the right explanation, but it is perfectly possible (and desirable) do avoid set! procedures. Here's an example of a procedure having the same result:
(define (rle lst)
(define (newpair c l res)
(if (> l 0) (cons (cons c l) res) res))
(let loop ((lst lst) (c #f) (l 0) (res '()))
(if (null? lst)
(reverse (newpair c l res))
(let ((n (car lst)))
(if (equal? c n)
(loop (cdr lst) c (add1 l) res)
(loop (cdr lst) n 1 (newpair c l res)))))))
such as
(rle '(1 1 1 2 2 2))
=> '((1 . 3) (2 . 3))
I've set up a procedure in scheme that will analyze a list and return the middle index when the list is odd, and the average of the middle 2 values when the list is even. Here's what I have (these ones run perfectly fine by themselves):
(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))
(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)) 2))
(median-index-iter2 (cdr lst) (+ 1 times_carred)))))
(median-index-iter2 lst 0))
Here's the actual procedure, without all the clutter from those helpers.
(define (median lst)
(if (null? lst)
'()
(if (even? lst)
(median-index-even lst)
(median-index-odd lst))))
However, when I try and run test cases, I get an error:
(display (median '(1 2 2 3 3 3 4 5))) (newline)
The object (1 2 2 3 3 3 4 5), passed as the first argument to integer-remainder, is not the correct type.
EDIT: Okay, yes, I completely overlooked the (even? (length lst)) part. I am currently debugging the helpers right now.
For starters this line is wrong, a list can not be even:
(if (even? lst)
A list's length, however, is a different matter:
(if (even? (length lst))
Also, in both procedures the comparison for determining if the list's mid point has been reached is wrong, you'll have to tweak this line in both helper procedures, because currently is not working:
(if (= times_carred ...
It'll be simpler if you start times_carred in 1 and change the condition to (>= times_carred (/ (length lst) 2)), the same comparison works for both cases.
I'm just starting with Scheme.
I'm trying to use some procedures from String Library.
Here's what I need:
input: "ccaAaAaAa"
function: generate all strings substituting all possible aAa to aBa, one substitution only
output: "ccaBaAaAa" and "ccaAaBaAa" and "ccaAaAaBa"
Is there any easy way to do that? Maybe a procedure that return a list of index of pattern found?
Apparently the searching function string-contains only returns the first occurrence.
What I thought is: after producing the first string "ccaBaAaAa", trim to the first index of the pattern found: the original "ccaAaAaAa" becomes "AaAaAa". Repeat (recursively).
Thanks.
string-contains won't give you a list of all occurrences of the substring, but it will tell you whether there is one, and if there is, what its index is. It also allows you to restrict the search to a particular range within the string. Based on this, if you get a match, you can recursively search the rest of the string until you no longer get a match.
From there, you can do the substitution for each match.
What is wrong by writing such a function?
(define (replace input)
(let loop ((done '())
(remaining (string->list input))
(output '()))
(if (pair? remaining)
(if (char=? #\a (car remaining))
(let ((remaining (cdr remaining)))
(if (pair? remaining)
(if (char=? #\A (car remaining))
(let ((remaining (cdr remaining)))
(if (pair? remaining)
(if (char=? #\a (car remaining))
(loop (append done (list #\a #\A))
remaining
(cons (list->string
(append done
(cons #\a
(cons #\B
remaining))))
output))
(loop (append done (list #\a #\A
(car remaining)))
(cdr remaining)
(reverse output)))
(reverse output)))
(loop (append done (list #\a (car remaining)))
(cdr remaining)
(reverse output)))
(reverse output)))
(loop (append done (list (car remaining)))
(cdr remaining)
(reverse output)))
(reverse output))))
(replace "ccaAaAaAa") ;=> ("ccaBaAaAa" "ccaAaBaAa" "ccaAaAaBa")
About 15 minutes work.
I thought there could be better string libraries that I didn't know about. But I end up doing what I'd proposed in the question. (For a general input case)
(define (aplicarRegra cadeia cadeiaOriginal regra n)
(let* ((antes (car regra))
(depois (cdr regra))
(index (string-contains cadeia antes))
(tamanho (string-length antes))
(diferenca (- (string-length cadeiaOriginal) (string-length cadeia))))
(if index
(let* ((cadeiaGerada (string-replace cadeiaOriginal depois (+ index diferenca) (+ index diferenca tamanho))))
(if(<= (string-length cadeiaGerada) n)
(lset-union equal? (list cadeiaGerada) (aplicarRegra(substring cadeia (+ 1 index)) cadeiaOriginal regra n))
(aplicarRegra (substring cadeia (+ 1 index)) cadeiaOriginal regra n)))
(list))))
But thanks anyway!