DrRacket : How to get the position of a value in a list - scheme

I am trying to get a list of positions of a value in a list in Intermediate Student Language.
For instance I wish a list of positions for value "A" in the following list
(list false A false false false false A false false false )
The output must be something like
(list 1 6)

Well there are a few things we can quickly understand, the first is that you're going to need to recurse through your initial list, and the second is that you're going to need to keep an accumulator list, and somehow have a notion of what element of the first list you're looking at, so we can also add a counter.
So,
; listsearch : (listof Any) Any -> (listof Int)
; Searches a list for val and returns a list of indexes for occurrences of val in lst
; (listsearch '(1 2 1 3 4 1) 1) => '(0 2 5)
(define (listsearch lst val)
(local [(define (helper lst acc counter)
(cond [(empty? lst) acc]
[(equal? val (first lst)) (helper (rest lst)
(cons counter acc)
(add1 counter))]
[else (helper (rest lst) acc (add1 counter))]))]
(reverse (helper lst empty 0))))
I've added a local because the counter should be present, but we want the actual function to be tidy, so the call is simply requiring a list and a value.
This simply goes through the list one by one, and makes three checks
Is the list empty? Return my accumulated list (base is empty)
Is the first item in the list my value? Start again but add that value to my accumulator and add one to my counter
Is the first item in the list something else? Start again but add one to my counter
This results in a backwards list, so we reverse it at the end.
That's it! :)

I'll give you some hints to solve this problem, it's much better if you reach a solution by your own means. Fill-in the blanks:
; position procedure
; lst: input list
; ele: the searched element
; idx: initial index, starts in 0
(define (position lst ele idx)
(cond (<???> ; if the input list is empty
<???>) ; then we're done, return the empty list
(<???> ; if the current element equals the one we're looking then
(cons <???> ; build output list, cons the index where we found it
(position <???> ele <???>))) ; and advance the recursion
(else ; otherwise
(position <???> ele <???>)))) ; just advance the recursion
Notice that the idx parameter is necessary to keep track of the index we're currently over, starting at zero. When the recursion advances, you must advance both the input list and the index. Don't forget to test the procedure:
(position '(false A false false false false A false false false) 'A 0)
=> '(1 6)

Related

create a scheme function that returns the average of negative numbers in a list

I'm trying to find the answer of my question but I can't find anything in the Internet. Can anyone please tell me how to write this function?
Thank you very much.
It's very easy. You can do it recursively:
(define (helper lst sum count)
...)
The helper does this using either cond of nested if:
as a base case when the list is empty it uses the values sum and count to calculate the average. eg. (helper '() -4 2) ; ==> -2
We know the list has at least one element. Check if the first element is negative. If so then it recurses with the rest of lst and using the sum of previous sum and the element and as count you increase the previous by 1. eg. (helper '(-1) 0 0) ; ==> (helper '() -1 1) ; ==> -1
just recruse with the rest of lst and keep the same values as sum and count. (helper '(1) -1 1) ; ==> -1
Now when you got this working you can just include it in your actual function and use it:
(define (average-negative lst)
(define (helper lst sum count)
...)
(helper lst 0 0))
Test
(average-negative '(-1)) ; ==> -1
(avwerage-negative '(1 -2 3 -4)) ; ==> -3
And for the brave:
(average-negative '()) ; ==> ??

How to convert a list into its elements

This must be very easy to accomplish but I am new to racket and dont know how:
I have a list (1 2 3 4) and would like to convert it into (1)(2)(3)(4)
Or is there a way to build it as (1)(2)(3)(4). I am using
cons '(element) call-function
to build it inside a function (recursively)
Try this:
(map list '(1 2 3 4))
From your text, I see that you do '(element). Problem with that is that everything which is quoted is never anything but what you see. Thus if element happens to be a variable it won't be expanded because of the quote.
The right way to get a list with one element would be to use list. eg. (list element) to get whatever the variable element to be the one element in your list. However, you won't need this in a roll-your-own recursive procedure:
(define (listify lst)
(if (null? lst) ; if lst is null we are done
'() ; evaluate to the empty list
(cons (list (car lst)) ; else we make a list with the first element
(listify (cdr lst))))) ; and listify the rest of the list too
Most of the procedure now is facilitating going through the argument, but since it's a common thing to do we can use higher order procedures with foldr so that you only concentrating on what is going to happen with the element in this chain in correspondence with the rest of the process:
(define (listify lst)
(foldr (lambda (e acc)
(cons (list e) ; chain this element wrapped in a list
acc)) ; with the result from the rest of the list
'() ; initiate with an empty list
lst)) ; go through lst
Of course, since we do something with each element in a list and nothing fancy by using map we only need to supply what to do with each element rather telling how to join the chains in the list together as well.
(define (listify lst)
(map list lst)) ; make a new list by applying a list of each element
It's actually a single argument version of zip:
(require srfi/1)
(zip '(1 2 3 4)) ; ==> ((1) (2) (3) (4))
(zip '(1 2 3) '(a b c)) ; ==> ((1 a) (2 b) (3 c))
There you go. As simple as it can get.

Scheme: a good set function

I need to write a good set function that checks whether its argument lst is a properly represented set, i.e. it is a list consisting only of integers, with no duplicates, and returns true #t or false #f. For example:
(good-set? (1 5 2)) => #t
(good-set? ()) => #t
(good-set? (1 5 5)) => #f
(good-set? (1 (5) 2)) => #f
so I have began writing the function as:
(define (good-set? lst)
so I don't know how to proceed after this. Can anybody help?
One option would be to use andmap and sets, as has been suggested by #soegaard:
(define (good-set? lst) ; it's a good set if:
(and (andmap integer? lst) ; all its elements are integers and
(= (length lst) ; the list's length equals the size
(set-count (list->set lst))))) ; of a set with the same elements
But if you can't use sets or other advanced procedures, then traverse the list and test if the current element is an integer and is not present somewhere else in the list (use member for this), repeating this test for each element until there are no more elements in the list. Here's the general idea, fill-in the blanks:
(define (good-set? lst)
(cond (<???> ; if the list is empty
<???>) ; then it's a good set
((or <???> ; if the 1st element is not an integer or
<???>) ; the 1st element is in the rest of the list
<???>) ; then it's NOT a good set
(else ; otherwise
(good-set? <???>)))) ; advance recursion
Sets are built into the Racket standard library: I would recommend not reimplementing them in terms of lists unless you really need to do something customized.
If we need to treat this as a homework assignment, I would recommend using a design methodology to systematically attack this problem. In this case, see something like How to Design Programs with regards to designing functions that work on lists. As a brief sketch, we'd systematically figure out:
What's the structure of the data I'm working with?
What tests cases do I consider? (including the base case)
What's the overall shape of the function?
What's the meaning of the natural recursion?
How do I combine the result of the natural recursion in order to compute a solution to the total?
For this, check if the first number is duplicated, if it is not, then recurse by checking the rest. As such:
(define (good-set? list)
(or (null? list) ; nothing left, good!
(let ((head (car list)))
(rest (cdr list)))
(and (number? head) ; a number
(not (member = head rest)) ; not in the rest
(good-set? rest))))) ; check the rest
If you need member, then
(define (member pred item list)
(and (not (null? list))
(or (pred item (car list))
(member pred item (cdr 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

List length in scheme

Hi I am trying to write a program where given a list of lists check to see if they are equal in size and return #t if they are.
So for example if i were to write (list-counter? '((1 2 3) (4 5 6) (7 8 9))) the program would return #t, and (list-counter? '((1 2 3) (4 5 6) (7 8))) would return #f.
SO far this is what I have done:
(define list-counter?
(lambda (x)
(if (list? x)
(if (list?(car x))
(let (l (length (car x))))
(if (equal? l (length(car x))))
(list-counter?(cdr x))
) ) ) ) )
I think where I am going wrong is after I set the length of l to the length of the first list. Any help would be appreciated.
There are several ways to solve this problem. For instance, by hand and going step-by-step:
(define (all-lengths lists)
(if (null? lists)
'()
(cons (length (car lists))
(all-lengths (cdr lists)))))
(define (all-equal? head lengths)
(if (null? lengths)
true
(and (= head (car lengths))
(all-equal? head (cdr lengths)))))
(define (list-counter? lists)
(let ((lengths (all-lengths lists)))
(all-equal? (car lengths) (cdr lengths))))
Let me explain the above procedures. I'm dividing the problem in two steps, first create a new list with the lengths of each sublist - that's what all-lengths does. Then, compare the first element in a list with the rest of the elements, and see if they're all equal - that's what all-equal? does. Finally, list-counter? wraps it all together, calling both of the previous procedures with the right parameters.
Or even simpler (and shorter), by using list procedures (higher-order procedures):
(define (list-counter? lists)
(apply = (map length lists)))
For understanding the second solution, observe that all-lengths and all-equal? represent special cases of more general procedures. When we need to create a new list with the result of applying a procedure to each of the elements of another list, we use map. And when we need to apply a procedure (= in this case) to all of the elements of a list at the same time, we use apply. And that's exactly what the second version of list-counter? is doing.
You could write an all-equal? function like so:
(define (all-equal? list)
;; (all-equal? '()) -> #t
;; (all-equal? '(35)) -> #t
;; (all-equal? '(2 3 2)) -> #f
(if (or (null? list) (null? (cdr list)))
#t
(reduce equal? list)
))
then do:
(all-equal? (map length listOfLists))
Alternatively you can do:
(define (lists-same-size? list-of-lists)
(if (== (length listOfLists) 0)
#t
(let*
(( firstLength
(length (car listOfLists)) )
( length-equal-to-first?
(lambda (x) (== (length x) firstLength)) )
)
(reduce and #t (map length-equal-to-first? listOfLists))
)
)))
What this says is: if the list length is 0, our statement is vacuously true, otherwise we capture the first element of the list's length (in the 'else' part of the if-clause), put it in the closure defined by let's syntactic sugar (actually a lambda), and use that to define an length-equal-to-first? function.
Unfortunately reduce is not lazy. What we'd really like is to avoid calculating lengths of lists if we find that just one is not equal. Thus to be more efficient we could do:
...
(let*
...
( all-match? ;; lazy
(lambda (pred list)
(if (null? list)
#t
(and (pred (first list)) (all-match? (cdr list)))
;;^^^^^^^^^^^^^^^^^^^ stops recursion if this is false
)) )
)
(all-match? length-equal-to-first? listOfLists)
)
)))
Note that all-match? is already effectively defined for you with MIT scheme's (list-search-positive list pred) or (for-all? list pred), or in Racket as andmap.
Why does it take so long to write?
You are forced to write a base-case because your reduction has no canonical element since it relies on the first element, and list manipulation in most languages is not very powerful. You'd even have the same issue in other languages like Python. In case this helps:
second method:
if len(listOfLists)==0:
return True
else:
firstLength = len(listOfLists[0])
return all(len(x)==firstLength for x in listOfLists)
However the first method is much simpler to write in any language, because it skirts this issue by ignoring the base-cases.
first method:
if len(listOfLists)<2:
return True
else:
return reduce(lambda a,b: a==b, listOfLists)
This might sound a bit weird, but I think it is easy.
Run down the list, building a new list containing the length of each (contained) list, i.e. map length.
Run down the constructed list of lengths, comparing the head to the rest, return #t if they are all the same as the head. Return false as soon as it fails to match the head.

Resources