this is a homework problem I'm stuck on. I have to create a function in Racket without using explicit recursion or local, that takes in a list of pairs, where the first element of each pair is a non-negative integer, and produces a new list of lists, where each list is k occurrences of the second element in each pair, where k is the first element of each pair. For example (expand-pairs (list (list 1 2) (list 3 4))) would produce (list (list 2) (list 4 4 4))
I got some code working, but only if the second element is a number. Since the question doesn't specify what type of element the second element is, I assume it needs to work for any element. So my function can solve the above example, but can't solve (expand-pairs (list (list 1 'a) (list 3 'b))).
Here is my code:
(define (expand-pairs plst)
(map
(lambda (x)
(map
(lambda (y) (+ (first (rest x)) y))
(build-list (first x) (lambda (z) (- z z)))))
plst))
My main problem is I don't know how to create a list of length k without using recursion or build-list, but then if I use build-list it creates a list of numbers, and I don't know how to convert that to a list of symbols or any other element.
Can anyone point me in the right direction?
Here's another possible implementation, building on #RomanPekar's answer but a bit more idiomatic for Racket:
(define (expand-pairs lst)
(map (lambda (s)
(build-list (first s) (const (second s))))
lst))
It makes use of the higher-order procedures map, const and build-list to create an implementation without using explicit recursion or local. The trick here is to understand how the following expression will return 5 copies of x:
(build-list 5 (const 'x))
^ ^ ^
#copies constant element
=> '(x x x x x)
Something like this:
(define (expand-pairs plst)
(map (lambda(x) (build-list (car x) (lambda(k) (cadr x)))) plst))
You don't have to use k in the build-list, just take second element of pair.
Related
I have a circular list, eg: #0=(1 2 3 4 . #0#).
What I want to do is to insert a new element (x) into this list so that the outcome is #0=(x 1 2 3 4 . #0#). I have been trying using this code (x is the circular list):
(define (insert! elm)
(let ((temp x))
(set-car! x elm)
(set-cdr! x temp)))
However, I think that set-cdr! is not working like I want it to. What am I missing here? Maybe I am way off?
The easiest way to prepend an element to a list is to modify the car of the list, and set the cdr of the list to a new cons whose car is the original first element of the list and whose cdr is the original tail of the list:
(define (prepend! x list) ; list = (a . (b ...))
(set-cdr! list (cons (car list) (cdr list))) ; list = (a . (a . (b ...)))
(set-car! list x)) ; list = (x . (a . (b ...)))
(let ((l (list 1 2 3)))
(prepend! 'x l)
(display l))
;=> (x 1 2 3)
Now, that will still work with circular lists, because the cons cell (i.e., pair) that is the beginning of the list remains the same, so the "final" cdr will still point back to object that is the beginning. To test this, though, we need some functions to create and sample from circular lists, since they're not included in the language (as far as I know).
(define (make-circular list)
(let loop ((tail list))
(cond
((null? (cdr tail))
(set-cdr! tail list)
list)
(else
(loop (cdr tail))))))
(define (take n list)
(if (= n 0)
'()
(cons (car list)
(take (- n 1)
(cdr list)))))
(display (take 10 (make-circular (list 1 2 3))))
;=> (1 2 3 1 2 3 1 2 3 1)
Now we can check what happens if we prepend to a circular list:
(let ((l (make-circular (list 1 2 3))))
(prepend! 'x l)
(display (take 15 l)))
;=> (x 1 2 3 x 1 2 3 x 1 2 3 x 1 2)
Since you're trying to prepend an element to a circular list, you need to do two things:
Insert a new cons cell at the front of the list containing the additional element. This is easy because you can just perform a simple (cons elm x).
You also need to modify the recursive portion of the circular list to point at the newly created cons cell, otherwise the circular portion will only include the old parts of the list.
To perform the latter, you need a way to figure out where the "end" of the circular list is. This doesn't actually exist, since the list is, of course, circular, but it can be determined by performing an eq? check on each element of the list until it finds an element equal to the head of the list.
Creating a helper function to do this, a simple implementation of insert! would look like this:
(define (find-cdr v lst)
(if (eq? v (cdr lst)) lst
(find-cdr v (cdr lst))))
(define (insert! elm)
(set! x (cons elm x))
(set-cdr! (find-cdr (cdr x) (cdr x)) x))
So I'm currently stuck on a "simple?" function in Racket. It's using the Intermediate Student with lambda language.
Some restrictions on this are that NO recursion is allowed, neither are local functions. It's plain and simple abstract list functions.
What this function is supposed to do is to take in a list of numbers, and output a list of pairs in which each pair has the first element as the number with the second element being the number it has occurred in the list.
Examples:
(1 1 2 3) => ((1 2) (2 1) (3 1))
(2 3 4 3) => ((2 1) (3 2) (4 1))
I have a function that produces the number of occurrences by inputting a list of numbers and a number which is:
(define (occurrences lon n)
(length (filter (lambda (x) (= x n)) lon)))
My approach, which was clearly wrong was:
(define (num-pairs-occurrences lon)
(list (lambda (x) (map (occurrences lon x) (remove x lon)) x))
I thought the above would work, but apparently my lambda isn't placed properly. Any ideas?
It's a bit trickier than you imagine. As you've probably noticed, we must remove duplicate elements in the output list. For this, is better that we define a remove-duplicates helper function (also using abstract list functions) - in fact, this is so common that is a built-in function in Racket, but not available in your current language settings:
(define (remove-duplicates lst)
(foldr (lambda (e acc)
(if (member e acc)
acc
(cons e acc)))
'()
lst))
Now it's easy to compose the solution using abstract list functions:
(define (num-pairs-occurrences lon)
(map (lambda (e) (list e (occurrences lon e)))
(remove-duplicates lon)))
The above might return and output list in a different order, but that's all right. And before you ask: yes, we do need that helper function. Please don't ask for a solution without it...
An easy, self-contained solution would be:
(define (num-pairs-occurences lst)
(foldl (lambda (e r)
(if (or (null? r) (not (= (caar r) e)))
(cons (list e 1) r)
(cons (list e (add1 (cadar r))) (cdr r))))
null
(sort lst >)))
Basically, you sort the list first, and then you fold over it. If the element (e) you get is the same as the first element of the result list (r), you increment the count, otherwise you add a new sublist to r.
If you sort by > (descending), you can actually use foldl which is more memory-efficient. If you sort by < (ascending), you need to use foldr which is less efficient.
I'm trying to write a function using Scheme that :
take a list of integers with more than two elements as a parameter
sum the n-th-element and (n+1)-th-element
return this list
Result should be as follows :
> (SumNeighbors (list 1 2 3 4))
(3 5 7)
I think I get the way to add elements but my recursion is totally wrong...
(define (SumNeighbors lst)
(if (not (null? (cdr lst)))
(append (list (+ (car lst) (car (cdr lst)))) (SumNeighbors (cdr lst)))))
Any help would be appreciated.
The solution to this problem follows a well-known pattern. I'll give you some hints, it'll be more fun if you find the answer by your own means:
(define (SumNeighbors lst)
(if <???> ; if there's only one element left
<???> ; we're done, return the empty list
(cons ; otherwise call `cons`
(+ <???> <???>) ; add first and second elements
(SumNeighbors <???>)))) ; and advance recursion
Notice the following:
Your solution is lacking the base case - what happens when the list we're traversing only has one element left? it's time to finish the recursion! and because we're building a list as the output, what should be the value returned?
We normally use cons to build an output list, not append. That's the natural way to build a list
The part of this procedure that falls outside the solution template is the fact that we stop when there's a single elment left in the list, not when the list is empty (as is the usual case)
You'll see that many procedures that iterate over an input list and return a list as output follow the same solution template, it's very important that you learn how and why this works, it's the foundation for writing solutions to other similar problems.
#!r6rs
(import (except (rnrs base) map)
(only (srfi :1) map))
(define (sum-neighbors lst)
(map + lst (cdr lst)))
The higher order function map as defined in SRFI-1 supports uneven lenght arguments. It will stop at the shortest list.
If you call (sum-neighbors '(1 2 3 4)) it will become (map + (1 2 3 4) (2 3 4)) which is the same as (cons (+ 1 2) (cons (+ 2 3) (cons (+ 3 4) '())))
How would you define a function which takes one argument, which should be a list, and returns the elements in the
list which are themselves lists?
(check-expect (find-sublists ’(1 2 () (3) (a b c) a b c))
’(() (3) (a b c)))
Do you have experience designing functions that can filter through a list?
A simpler problem with the same flavor as the original is something like this: design a function that takes a list of numbers and keeps only the even numbers. Would you be able to do that function?
Looking at http://www.ccs.neu.edu/home/matthias/HtDP2e/htdp2e-part2.html and going through its guided exercises may also help.
Two useful tools which should start you on your way:
1) Traversing through a list:
; traverse: takes a list of numbers
; Goes through each element, one-by-one, and alters it
(define traverse
(lambda (the_list)
(if (empty? the_list)
empty
(cons (+ 1 (first the_list))
(traverse (rest the_list))))))
(traverse (cons 3 (cons 4 empty))) returns (cons 4 (cons 5 empty))
2) list?:
(list? (list 1 2 3)) returns #t
(list? 5) returns #f
i am trying to do the following in Scheme:
List<int> list = new List<int>();
List<int> list1 = new List<int>();
List<int> list2 = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
list1.Add(2);
list1.Add(4);
list1.Add(6);
list1.Add(8);
for (int i = 0; i < list.Count; i++)
{
for (int p = 0; p < list1.Count; p++)
{
list2.Add(list[i] * list1[p]);
}
}
as seen in the code above, I am trying to multiply each element of the first list with every element in the second list. So 1*2, 1*4, 1*6, 1*8, then going to the next element, 2*2,2*4.. etc.
I am having trouble implementing this into Scheme. I tried using the map function but this doesn't seem to work the way I want it to. Any ideas?
We start by defining the two input lists, I renamed them since list is a built-in procedure in Scheme and is not a good idea to overwrite it):
(define l '(1 2 3 4))
(define l1 '(2 4 6 8))
I'm assuming that you want your result list to be "flat" - e.g., it doesn't contain lists of elements, only elements (if you're ok with having a list of lists in l2, simply delete the call to flatten below). For that, we need to define the flatten procedure:
(define (atom? x)
(and (not (pair? x)) (not (null? x))))
(define (flatten lst)
(cond ((null? lst) empty)
((atom? lst) (list lst))
(else (append (flatten (car lst))
(flatten (cdr lst))))))
Finally, the problem at hand. It's simple once you understand how to nest two map procedures - take a look at the nested mappings section in the book SICP.
(define l2
(flatten
(map (lambda (i)
(map (lambda (j)
(* i j))
l1))
l)))
At this point, l2 contains the expected answer:
(2 4 6 8 4 8 12 16 6 12 18 24 8 16 24 32)
Óscar has given a very complete answer to this question, but I wanted to add two minor notes:
The Scheme dialect Racket has a nice built-in form called for*/list which does exactly this sort of thing:
(for*/list ([i '(1 2 3 4)]
[j '(2 4 6 8)])
(* i j))
Also, instead of using your own or the library's flatten function in the nested-maps solution, you could replace the outer map with append-map from SRFI-1. There are plenty of other ways too, of course ;-)
I can't believe nobody has given the most straightforward answer: nested uses of map:
(append-map (lambda (x)
(map (lambda (y) (* x y))
(list 2 4 8 6)))
(list 1 2 3 4))
append-map is a simple variant of map that assumes that the mapping function returns a list, so it concatenates all the result lists. This is a library function in most serious Scheme systems (it's in the SRFI-1 library), but here's a simple, incomplete definition (a complete definition would handle multiple argument lists):
(define (append-map f xs)
(concat (map f xs)))
;;;
;;; Turns a list of lists into a list by appending all the top-level sublists.
;;; This is also a common library function.
;;;
(define (concat lists)
(if (null? lists)
'()
(append (car lists)
(concat (cdr lists)))))