Create Python's collections.counter() method in Beginner Racket - racket

The goal is to create a function that accepts a list of symbols and produces a list of key value pairs that count how many times each symbol in list appears. eg:
(counter (list 't 't 'c 'a)) -> (list (list 't 2) (list 'c 1) (list 'a 1))
The function must be completed with recursion
I've only gotten as far as to create a list of key value pairs that treat duplicates as standalone values:
(define val 0)
(define (counter los)
(cond
[(empty? los) empty]
[else (cons (list (first los) (add1 val))
(counter (rest los)))]))
(counter (list 't 't 'c 'a)) -> (list (list 't) (list 't) (list 'c 1) (list 'a 1))

It has been a very long time since I used BSL but I believe these operations are all present. There may be a cleaner way of doing this but I will leave it up to you to check the documentation and simplify it if possible
(define (counter los) (counter-helper los empty))
(define (counter-helper los lists)
(cond
[(empty? los) lists]
[else (if (list? (assq (first los) lists))
(counter-helper
(rest los)
(cons (list (first los) (add1 (second (assq (first los) lists))))
(remove (assq (first los) lists) lists)))
(counter-helper (rest los) (cons (list (first los) 1) lists)))]))
the if statement checks if there is already an entry in our list of lists for that key, it returns the pair if yes, false otherwise.
If the result is false we just append a new pair with value 1 and recur.
If it already exists, we construct a new pair from the previous one, with the same key, but the value incremented and append this new pair to our list of lists - the previous pair removed

Related

Don't know how to solve this error [Racket]: "car: contract violation expected: pair? given: '()"

I'm trying to get a list with the average of the following n elements. I'm reading a csv file that has 7 columns im just using the 6th one that has number values in order to get the average.
This is the code
;Function that returns a list containing the values of the desired column
(define (get-column col)
(let loop
([file (cdr(all-rows csv-path read-csv))]
[result empty])
(if (empty? file)
result
(loop (cdr file)
(cond
[(equal? col 1) (append result (list (caar file)))]
[(equal? col 2) (append result (list (string->number(cadar file))))]
[(equal? col 3) (append result (list (string->number(caddar file))))]
[(equal? col 4) (append result (list (string->number(car (cdddar file)))))]
[(equal? col 5) (append result (list (string->number(cadr (cdddar file)))))]
[(equal? col 6) (append result (list (string->number(caddr (cdddar file)))))]
[(equal? col 7) (append result (list (string->number(car (cdddr (cdddar file))))))]
)))))
(define (suma-SMA col n)
(let loop
([n n]
[res 0]
[col col])
(if (zero? n)
res
(loop (sub1 n) (+ res (car col)) (cdr col)))))
(define (get-SMA days)
(let loop
([col (get-column 6)]
[result empty])
(if (empty? col)
result
(loop (cdr col)(append result (list (suma-SMA col days)))))))
Here's a function that does what you asked for in the comments, e.g. given (1 2 3 4) it produces ((1+2)/2 (2+3)/2 (3+4)/2).
(define (sum list)
(cond
((null? list)
'()) ;; error?
((null? (cdr list))
'())
(else
(cons (/ (+ (car list) (cadr list)) 2) (sum (cdr list))))))
I'm still a bit confused because even the combination of get-SMA and suma-SMA does nothing like this. It's completely unclear what the days variable is doing, as you can see I didn't need it in my code above.
So I may have misunderstood what you are trying to do, but the function above does what you actually asked for so hopefully it will be helpful.
Here is the answer that I found useful for my problem.
(define (sum list n)
(cond
((null? list)
'()) ;; error?
((null? (cdr list))
'())
(else
(cons (suma-SMA list n) (sum (cdr list) n)))))

How can I just use high order functions to rewrite these (use Dr.Racket)

This is my homework but we are only allowed to use filter, map, foldr, sort, build-list, and lambda instead of the explicit recursion
How can I rewrite these use those high order functions above to not let the function call itself.
What I have now are these:
(define (worthless loc name)
(cond
[(empty? loc) loc]
[(equal? name (coin-name (first loc))) (cons (make-coin (coin-name (first loc)) 0) (worthless (rest loc) name))]
[else (cons (first loc) (worthless (rest loc) name))]))
(define (working-group locations group-tz)
(cond
[(empty? locations) empty]
[(and (equal? (utc-hours group-tz) (utc-hours (location-timezone (first locations)))) (equal? (utc-sign group-tz) (utc-sign (location-timezone (first locations)))))
(cons (location-city (first locations)) (working-group (rest locations) group-tz))]
[(and (equal? (add1 (utc-hours group-tz)) (utc-hours (location-timezone (first locations))))
(equal? (utc-sign group-tz) (utc-sign (location-timezone (first locations))))
(equal? (utc-mins group-tz) (utc-mins (location-timezone (first locations)))))
(cons (location-city (first locations)) (working-group (rest locations) group-tz))]
[(and (equal? (sub1 (utc-hours group-tz)) (utc-hours (location-timezone (first locations))))
(equal? (utc-sign group-tz) (utc-sign (location-timezone (first locations))))
(equal? (utc-mins group-tz) (utc-mins (location-timezone (first locations)))))
(cons (location-city (first locations)) (working-group (rest locations) group-tz))]
[else (working-group (rest locations) group-tz)])) ```
Yes. worthless can be rewritten with map. Imagine we have this function that adds 3 to each element in a list:
(define (add3 lst)
(if (null? lst)
'()
(cons (+ (car lst) 3)
(add3 (cdr lst)))))
Map for one list looks like this:
(define (map f lst)
(if (null? lst)
'()
(cons (f (car lst))
(map f (cdr lst))))
Looking at these you can see that an add3 with map only needs to focus on adding 3. Basically you need to pass a function with one argument that adds 3 to that argument:
(define (add3-wm lst)
(map (lambda (v) (+ v 3)) lst))
Now foldr for one list looks like this:
(define (foldr f init lst)
(if (null? lst)
init
(f (car lst)
(foldr f init (cdr lst)))))
Here you see that cons isn't done so rewriting add3 using foldr takes a combiner and it needs to add 3 to the first argument and combine the two arguments where the second argument is the result fo the same process with the later elements.
(define (add3-fr lst)
(define (combiner v acc)
(cons (+ v 3) acc))
(foldr combiner '() lst))
In reality using foldr here is overkill, but it would be interesting if you sometimes needed to skip an element like working-group does. In that case the combiner just returns the second argument. You can make filter with foldr:
(define (filter f lst)
(foldr (lambda (v acc)
(if (f v)
(cons v acc)
acc))
'()
lst))
Good luck

Racket - Add or remove element from a 2dlist

I'm doing a problem which asks me to write a function that consumes a
list (dict1) and a list (act) that contains an action (remove or add) and a value. The updates should adhere to the following specifications:
• If the first element of act is “remove" and the key is in the dictionary, then the matching value in the associated list should be removed.
• If the matching value happens to be the last element in the associated list, then the key should remain in the dictionary, but the associated list becomes empty. If the value is not in the dictionary, the dictionary does not change.
• If the value of act is "add" and the key is in the dictionary, then the new value
should be added to the associated list in the dictionary if it does not already exist. If the value already exists in the associated list, the updated dictionary would not change.
• If the value of act is “add" and the key does not exist in the dictionary, then a
new association list entry for the key should be added to the dictionary.
For example:
(define dict1 (list (list "Num" (list 5 1.3 -1))
(list "Char" (list #\p))
(list "Str"
(list "cs" "CS" "Computer Science"))))
Then
(update dict1 (list "add" true)) =>
(list (list "Num" (list 5 1.3 -1))
(list "Bool" (list true))
(list "Char" (list #\p))
(list "Str" (list "cs" "CS" "Computer Science")))
(update dict1 (list "remove" "cs")) =>
(list (list "Num" (list 5 1.3 -1))
(list "Char" (list #\p))
(list "Str" (list "CS" "Computer Science")))
I could only come up with the first step, below is what I have so far:
(define (update dict1 act)
(cond
[(equal? (first act) "remove") (remove-value dict1 (second act))]
[(equal? (first act) "add") (add-value dict1 (second act))]))
For this question I'm only allowed to use member? or remove.
I knew that I've been asking a lot of questions in the past couple of days, but I am new to racket and I am doing my best to learn it :( Please help
no set! no local version
; please tell us which language you use (in front of code)
#|
In Beginning Student Language variabe can't be function
error: function call: expected a function after the open parenthesis, but found a variable
(define (f fn) (fn 1))
(f add1)
|#
; use "Advanced Student" language or "#lang racket".
#lang racket
(define dict1
(list (list "Num" (list 1 2 3))
(list "Char" (list #\p))
(list "Bool" '())
(list "Str" (list "a" "b" "c"))))
(define (index-title action)
(cond
[(number? (second action)) 0]
[(char? (second action)) 1]
[(boolean? (second action)) 2]
[(string? (second action)) 3]
[else (error "type error")]))
(define (my-remove word lst)
(cond
[(empty? lst) empty]
[(equal? word (first lst))
(rest lst)]
[else
(cons (first lst)
(my-remove word (rest lst)))]))
(define (exist? word lst)
(cond
[(empty? lst) #f]
[(equal? word (first lst)) #t]
[else
(exist? word (rest lst))]))
(define (add-if-not-exist word data)
(if (exist? word data)
data
(cons word data)))
(define (action-to-data word data action)
(cond
[(equal? action "add")
(add-if-not-exist word data)]
[(equal? action "remove")
(my-remove word data)]))
(define (aux-build-list i n dict act a-function)
(cond
[(= i n) empty]
[else
(cons (a-function i dict act)
(aux-build-list (+ i 1) n dict act a-function))]))
(define (my-build-list n dict act a-function)
(aux-build-list 0 n dict act a-function))
(define (build-new-sub-dict n dict act)
(cond
[(= n (index-title act))
(list (first (list-ref dict n))
(action-to-data (second act) (second (my-list-ref dict n)) (first act)))]
[else
(list-ref dict n)]))
(define (my-list-ref lst n)
(cond
[(< n 0) (error "error")]
[(= n 0) (first lst)]
[else
(my-list-ref (rest lst) (- n 1))]))
(define (update dict act)
(set! dict1
(my-build-list (length dict)
dict
act
(lambda (n dict act) (build-new-sub-dict n dict act)))))
;;; Test
(update dict1 '("add" 2))
(update dict1 '("remove" 3))
(update dict1 '("add" 4))
(update dict1 '("add" 4))
(update dict1 '("remove" 1))
(update dict1 '("remove" 2))
dict1

how to iterate through a list in racket? if the character in the list is alphabetic, I want to add to a new string

Here is my code? Can anyone tell me how to iterate through a list? if the character in the list is alphabetic, I want to add to a new string
#lang racket
(define (conversion input)
(define s (string))
(let ((char (string->list input)))
(cond
[(char-alphabetic? (first (char)))
(string-append s first)]
[(char-alphabetic? (rest (char)))
(string-append s rest)]))
(display s))
Basic iteration is:
(define (copy-list lst)
(if (null? lst)
'()
(cons (car lst)
(copy-list (cdr lst))))
(copy-list '(1 2 3)) ; ==> (1 2 3)
This one actually makes a shallow copy of your list. Sometimes you iterate with keeping some variables to accumulate stuff:
(define (sum-list lst acc)
(if (null lst)
acc
(sum-list (cdr lst) (+ acc (car lst)))))
(sum-list '(1 2 3)) ; ==> 6
Looking at these you'll see a pattern emerges so we have made stuff like map, foldl, and foldr to abstract the iteration:
(define (copy-list-foldr lst)
(foldr cons '() lst)
(define (copy-list-map lst)
(map values lst))
(define (sum-list-foldl lst)
(foldl + 0 lst))
Looking at your challenge I bet you can fix it with a foldr.

Calculating the number of matches for every sublist separately

Here is my big list with sublists:
(define family
(list
(list 'Daddy 't-shirt 'raincoat 'sunglasses 'pants 'coat 'sneakers)
(list 'Mamma 'high-heels 'dress 'pants 'sunglasses 'scarf)
(list 'son 'pants 'sunglasses 'sneakers 't-shirt 'jacket)
(list 'daughter 'bikini 'Leggings 'sneakers 'blouse 'top)))
And i want to compare family with this simple list:
(list 'sneakers 'dress 'pants 'sunglasses 'scarf)
each matching should give 1 point and i want that the point to be calculated separately for each sublist.
Here is the code:
;checking if an element exists in a list
(define occurs?
(lambda (element lst)
(cond
[(and (null? element) (null? lst))]
[(null? lst) #f]
[(pair? lst)
(if
(occurs? element (car lst)) #t
(occurs? element (cdr lst)))]
[else (eqv? element lst)])))
;--------------------------------------
; a list of just names are created.
(define (name-list lst)
(list (map car lst)))
; Each sublist has a name (car of the sublist). The name-list turn to point-list for each sublist. All of my code except the code below is functioning as i want. The problem lies within point-list code.
(define (point lst db)
(let ((no-point (name-list db)))
(cond ((or (null? lst) (null? db)) '())
(set! (first no-point) (comp lst (rest db)))
(else (point lst (cdr db))))))
Daddy-sublist has 3 elements in common. Mamma-sublist has 4 elements in common, son-sublist 3 elements and daugther-sublist 1 element.
I want the outdata to be like this:
> (comparison (list 'sneakers 'dress 'pants 'sunglasses 'scarf) family)
'(3 4 3 1)
My code is not functioning as I want it. I get this Eror :
set!: bad syntax in: set!
Can someone guide explain me what to do?
You have bad syntax with set!:
(set! (first no-point-lst) (comparison lst (rest db)))
This is an invalid use of set!, attempting to "mutate the structure" of the list no-point-lst, changing what's actually held in its first position.
set! can't do that. It can be used to change a binding, i.e. the value of a variable: (let ((a 1)) (set! a 2)).
In Common Lisp they can write (setf (first list) newval), but not in Scheme / Racket.
If this is essential to your algorithm, you can use set-car! in R5RS Scheme, or set-mcar! in Racket. Or you could do this with vectors.
But you could also restructure your code as
(set! no-points-list
(cons
(comparison lst (rest db))
(cdr no-points-list)))