I need to write a function that produces the nth column of a matrix in Racket without using recursion. For example (list (list 1 2 3) (list 2 3 4) (list 6 7 9)) if I wanted the 2nd column I would receive (list 2 3 7).
I tried (append (map (lambda (n) (list-ref (list-ref M) n) n)) M)), but it keeps showing me an error.
The attempted solution uses list-ref twice, which is not needed, and one of those calls does not have enough arguments: (list-ref M) has the function taking only one argument, but it requires two arguments -- a list and an integer.
The list-ref function will return an indexed element from an input list, so (list-ref '(1 2 3) 1) will return 2. Consider what map will do here: the matrix is represented as a list of lists (a list of rows), i.e., as ((1 2 3) (2 3 4) (6 7 9)). The map function will act on the members of the input list, which are the lists (1 2 3), (2 3 4), and (6 7 9). By mapping the list-ref function over that input, you can take whichever element you want from the sublists. So, (map (lambda (row) (list-ref row 1)) '((1 2 3) (2 3 4) (6 7 9))) would evaluate to (2 3 7), as desired.
Here is a function that lets you take any column from a matrix:
(define (nth-column M n)
(map (lambda (row) (list-ref row n)) M))
Sample interactions:
scratch.rkt> (define M '((1 2 3)
(2 3 4)
(6 7 9)))
scratch.rkt> (nth-column M 1)
'(2 3 7)
scratch.rkt> (nth-column M 0)
'(1 2 6)
scratch.rkt> (nth-column M 2)
'(3 4 9)
Related
I'm trying to learn a Lisp language and have settled on Guile and am trying to solve this problem:
You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money.
Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.
You may assume that you have an infinite number of each kind of coin.
Fundamentally, I understand the basic of dynamic programming where you can use recursion and memoization in order to save calculating at lower depths, but as Lisp I would expect it to be perfect for this type of problem. The problem I am having is returning separate lists for each combination of coins.
For an example case, consider target of 6 with coins [2, 3]. The simple tree would look like this:
The correct answer would be (3 3) with the other "complete" solution being (2 2 2).
However, if I try and construct these, the form I would want to use (without memoization) would look something like this.
(define get-coins (lambda (coins target)
(cond
((= target 0) '())
; not quite sure how to "terminate" a list here
; An idea is to return (list -1) and then filter
; lists that contain -1
((< target 0) ?????)
(else
; for each coin, recurse
(map (lambda (v)
(cons v (get-coins coins (- target v))))))
)
))
However, this doesn't return more lists as it goes through. Rather, it creates nested lists. And this is my problem. Any help with this would be greatly appreciated.
I wanted to avoid nested lists, so I used a variable results:
(define (get-coins coins target)
(let ((results '()))
Then I defined the function get-coins-helper, similar to your get-coins. And whenever I found some possible result, I used set! to update results:
(letrec ((get-coins-helper
(lambda (coins target result)
(cond ((= target 0) (set! results (cons result results)))
((< target 0) '())
(else (map (lambda (value)
(get-coins-helper coins
(- target value)
(cons value result)))
coins))))))
Then I called (get-coins-helper coins target '()) to find all possible results and at the end, I checked the value of results and returned -1 (if results are empty) or the shortest element of results:
(if (null? results)
-1
(car (sort results (lambda (x y) (< (length x)
(length y))))))
Full code:
(define (get-coins coins target)
(let ((results '()))
(letrec ((get-coins-helper
(lambda (coins target result)
(cond ((= target 0) (set! results (cons result results)))
((< target 0) '())
(else (map (lambda (value)
(get-coins-helper coins
(- target value)
(cons value result)))
coins))))))
(get-coins-helper coins target '())
(if (null? results)
-1
(car (sort results (lambda (x y) (< (length x)
(length y)))))))))
Some tests:
> (get-coins '(2 3) 6)
'(3 3)
> (get-coins '(2 3) 1)
-1
Using fold to choose best solutions. The result is a list whose car is the number of coins and cdr is the list of chosen coins. In the event that no solutions are feasible, (+inf.0) is returned.
(use-modules (srfi srfi-1))
(define (get-coins coins target)
(fold (lambda (coin best)
(let [(target (- target coin))]
(cond [(zero? target)
(list 1 coin)]
[(positive? target)
(let* [(res (get-coins coins target))
(score' (1+ (car res)))]
(if (< score' (car best))
(cons score' (cons coin (cdr res)))
best))]
[(negative? target)
best])))
(list +inf.0)
coins))
(get-coins (list 2) 6)
$8 = (3 2 2 2)
(get-coins (list 2 3) 6)
$9 = (2 3 3)
(get-coins (list 9) 6)
$10 = (+inf.0)
If you read the question carefully, all you need to keep track of is the number of coins needed to reach the target amount. You don't have generate every possible combination of coins to reach the target, just the one that minimizes the number of coins. And you don't even have to remember what that particular combination is, just its length. This simplifies things a bit since there's no need to build any lists.
For each denomination of coin that can possibly be used to reach the goal (So no coins bigger than the difference between the goal and the current sum), get the counts for using one of them and for using none of them, and return the minimum (Or -1 if no options present themselves).
(define (get-coins coins target)
(calculate-coins coins 0 0 target))
;; Do all the work in a helper function
(define (calculate-coins coins coin-count amount target)
(cond
((= amount target) coin-count) ; Success
((null? coins) -1) ; Failure
((> (car coins) (- target amount)) ; Current coin denomination is too big; skip it
(calculate-coins (cdr coins) coin-count amount target))
(else
;; Cases to consider:
;; Adding one of the current coin to the total and leaving open using more
;; Not using any of the current coins
(let ((with-first
(calculate-coins coins (+ coin-count 1) (+ amount (car coins)) target))
(without-first
(calculate-coins (cdr coins) coin-count amount target)))
(cond
((= with-first -1) without-first)
((= without-first -1) with-first)
(else (min with-first without-first)))))))
If you do want to get every possible combination of coin, one way is to, for each list of combinations that use a given coin, use append to combine it with a list of previous ways:
(use-modules (srfi srfi-1))
(define (get-coins2 coins target)
(define (helper target) ; This time define a nested helper function
(fold
(lambda (coin ways)
(cond
((= coin target) (cons (list coin) ways))
((< coin target)
(append
(map (lambda (c) (cons coin c))
(helper (- target coin)))
ways))
(else ways)))
'()
coins))
(let* ((ways (helper target))
(table (make-hash-table (length ways))))
;; Store each combination as a key in a hash table to remove duplicates
(for-each (lambda (way) (hash-set! table (sort-list way <) #t)) ways)
(hash-map->list (lambda (k v) k) table)))
Examples:
scheme#(guile-user)> (load "coins.scm")
scheme#(guile-user)> (get-coins '(2) 6)
$1 = 3
scheme#(guile-user)> (get-coins2 '(2) 6)
$2 = ((2 2 2))
scheme#(guile-user)> (get-coins '(2 3) 6)
$3 = 2
scheme#(guile-user)> (get-coins2 '(2 3) 6)
$4 = ((2 2 2) (3 3))
scheme#(guile-user)> (get-coins '(9) 6)
$5 = -1
scheme#(guile-user)> (get-coins2 '(9) 6)
$6 = ()
scheme#(guile-user)> (get-coins2 '(2 3) 12)
$7 = ((3 3 3 3) (2 2 2 3 3) (2 2 2 2 2 2))
scheme#(guile-user)> (get-coins '(5 2 3 4) 21)
$8 = 5
scheme#(guile-user)> (get-coins2 '(5 2 3 4) 21)
$9 = ((2 2 2 5 5 5) (2 3 3 4 4 5) (2 4 5 5 5) (3 3 3 4 4 4) (2 2 3 4 5 5) (4 4 4 4 5) (2 2 4 4 4 5) (2 2 3 3 3 4 4) (2 2 2 2 2 3 4 4) (2 2 2 2 4 4 5) (3 3 3 3 4 5) (2 2 2 2 3 3 3 4) (2 2 2 2 2 2 2 3 4) (2 2 2 2 2 2 4 5) (3 3 3 3 3 3 3) (2 2 3 3 3 3 5) (2 2 2 2 2 2 3 3 3) (2 2 2 2 2 3 3 5) (3 3 5 5 5) (2 2 2 2 2 2 2 2 2 3) (2 2 2 2 3 5 5) (2 2 2 2 2 2 2 2 5) (2 3 4 4 4 4) (2 2 2 3 4 4 4) (2 3 3 3 3 3 4) (2 2 2 3 3 4 5) (2 2 2 3 3 3 3 3) (2 3 3 3 5 5) (3 4 4 5 5))
scheme#(guile-user)> (filter (lambda (way) (= (length way) 5)) (get-coins2 '(5 2 3 4) 21))
$10 = ((2 4 5 5 5) (4 4 4 4 5) (3 3 5 5 5) (3 4 4 5 5))
There are many ways to do it, here is a brute-force solution. It is not elegant but it is simple.
(define mk/pairs
(lambda (sum coin/list)
((lambda (s) (s s
(map (lambda (x) (iota (+ 1 (quotient sum x)))) coin/list)
(lambda (s) s) ))
(lambda (s l* ret)
(if (null? l*)
(ret '(()))
(s s (cdr l*)
(lambda (r)
(ret (apply
append
(map (lambda (x) (map (lambda (y) (cons y x)) (car l*)))
r))))))))))
(define cost
(lambda (s pair coin/list)
(let ((sum (apply + (map * pair coin/list))))
(and (= s sum) pair))))
(define solve
(lambda (sum coin/list)
(let ((pairs (mk/pairs sum coin/list)))
(let ((solutions
(sort (filter (lambda (x) x)
(map (lambda (p) (cost sum p coin/list)) pairs))
(lambda (p1 p2)
(< (apply + p1)
(apply + p2))))))
(if (null? solutions)
"fail"
(car solutions))))))
A test looks like so:
% mit-scheme < coins.scm
MIT/GNU Scheme running under GNU/Linux
1 ]=> (solve 8 '(2 3 1))
;Value: (1 2 0)
1 ]=> (solve 6 '(2 3))
;Value: (0 2)
meaning that you have 1 coin of 2 and 2 coins of 3 in the first example and 2 coins of 3 in the second example.
I have used standard R6RS, so you should be able to convert it directly from mit/scheme to guile.
How could I address this problem?
Given a function of arity 1 and a list, return a list of applying the function to each element of the original list. For example:
(Mmap add1 '(1 2 3 4)) ; -> '(2 3 4 5)
(Mmap car '((1 2 3) (4 5 6) (7 8 9))) ; -> '(1 4 7)
(Mmap cdr '((1 2 3) (4 5 6) (7 September 8))) ; -> '((2 3) (5 6) (8 9))
I've tried cond and other similar functions, but I really have little idea how to solve it.
(define (myfunc f alist)
(cond
[(empty? alist) empty]
[else (cons (f (first alist)) (myfunc f (rest alist)))]
))
f is your function (e.g. add1, car) and alist is your argument. All you have to do is to construct a list where you apply f to your first argument, and append the rest of the list recursively to that.
Regarding your last example. I assume that September was defined previously as (define September 8). In that case your example won't give you your desired output. The last list will contain 'September instead of 8, because you declared your list with '(), which treats names as symbols.
Furthermore, the output should be '((2 3) (5 6) (8 8)) given that cdr returns the second and subsequent elements of a list. So you probably want (list 7 September 9) as your last list in your input, so that you get '((2 3) (5 6) (8 9)) instead.
You'd have to call the function like this: (myfunc cdr (list (list 1 2 3) (list 4 5 6) (list 7 September 9)))
Edit: Obviously it would make most sense to define September as 9, as it's the ninth month of the year, and call the function like this: (myfunc cdr (list (list 1 2 3) (list 4 5 6) (list 7 8 September)))
Mmap can be defined in terms of #lang racket's function map.
(define Mmap map)
I have such code in Scheme:
(define transpose2 ;1
(lambda (A T) ;2
(if (pair? (car A)) ;3
(transpose2 ;4
(map cdr A) (cons (map car A) T) ;5
) ;6
(reverse T) ;7
) ;8
) ;9
) ;10
I have trouble understanding line nr 5. How creating a pair in this line eventually leads to transposing given matrix?
(define transpose ;1
(lambda (A) ;2
(transpose2 A `()) ;3
) ;4
) ;5
previous function transpose2 is executed by this function and for example:
(display (transpose '((1 2) (3 4) (5 6))))
(display (transpose '((3 2 1) (2 1 1) (3 1 1))))
gives results:
((1 3 5) (2 4 6))
((3 2 3) (2 1 1) (1 1 1))
There are two parameters here: A, your original matrix, and T, your accumulator.
On line 3, we check if the first element of A is a list, e.g. in the form '(1). If so, then we recurse, reducing A by one column with (map cdr A) and accumulating the first member of each A into T. When we finally exhaust our list, we reverse our accumulator and return it.
The code could perhaps be made slightly clearer if the condition on line 3 was replaced with (not (empty? A)).
Example trace:
(transpose '((1 2) (3 4) (5 6)))
-> (transpose2 '((1 2) (3 4) (5 6)) '())
-> (transpose2 (map cdr A) (cons (map car A) T))
-> (transpose2 '((2) (4) (6)) '((1 3 5)))
-> (transpose2 '(() () ()) '((2 4 6) (1 3 5)))
-> (reverse '((2 4 6) (1 3 5)))
-> '((1 3 5) (2 4 6))
When you use foldr, the procedure you use has 2 arguments, the current value of the list and the accumulator. Let's say the list you iterate over is a list of list of numbers, all the same length. Then as you iterate through them, you want to multiply the numbers of the same index and store it as the accumulator.
If you use lambda (x acc) (map * x acc) inside the foldr, this fails because acc I believe is an empty list in the beginning. How can you handle the base case like this?
This can be solved using foldr all right, the trick is to correctly initialize the accumulated value at the beginning. No need to do fancy stuff (like macros) here!
(define lst '((1 2 3) (2 3 5) (3 5 7)))
(foldr (lambda (x acc) (map * x acc))
(car lst)
(cdr lst))
=> '(6 30 105)
Of course, if the list is empty (car lst) will fail. So you might want to handle the empty list as a separate case before invoking foldr.
Say you have a list of lists as follows:
((1 2 3) (2 3 5) (3 5 7))
You want to reduce it to:
(6 30 105)
I would simple do:
(define-syntax mul
(syntax-rules ()
((_ (lists ...)) (map * 'lists ...))))
The you can use it as follows:
(mul ((1 2 3) (2 3 5) (3 5 7))) ; => (6 30 105)
The above code simply expands to:
(map * '(1 2 3) '(2 3 5) '(3 5 7))
Then you can fold the resulting list. For example:
(foldr + 0 (mul ((1 2 3) (2 3 5) (3 5 7)))) ; => 141
I wanted to write the code for comparing the size of two lists. I made use of the length and wrote this down.
(define (same-size-matrix? mtrx1 mtrx2)
(equal? (length mtrx1) (length mtrx2))).
I thought this was going to work for me, but I found out it only checks the overall length, not the sublist. For example it returns true when it compares for. '((1 2 3 4) (4 5 6 6) (6 7 8 9)) and '(( 5 4) (3 2) (7 1)), but it's supposed to return false, because the first has 4 values within the list and the second has only two even though they both overally have same length. How do I go about this. Any help would be appreciated.
Try this instead:
(define (same-size-matrix? mtrx1 mtrx2)
(equal? (map length mtrx1) (map length mtrx2)))
Notice that in your solution you're comparing the total length of each list (the number of rows in the matrix), but ignoring the length of each sublist (the number of columns for each row in the matrix). In my soultion, first we calculate the length of each sublist and after that we check if all the lengths are equal. For example, take this input:
(define mtrx1 '((1 2 3 4) (4 5 6 6) (6 7 8 9)))
(define mtrx2 '((5 4) (3 2) (7 1)))
(same-size-matrix? mtrx1 mtrx2)
First the same-size-matrix? evaluates this expression, which finds the length of each sublist in mtrx1. It's necessary to check all the lengths, not just the first one, in case we're dealing with a jagged array:
(map length mtrx1)
; evaluates to '(4 4 4)
And then we have this expression, which performs the same operation for mtrx2:
(map length mtrx2)
; evaluates to '(2 2 2)
Finally, we compare the two lists of lengths (in fact: the number of columns per row), returning the expected result:
(equal? '(4 4 4) '(2 2 2))
> #f
Notice that the last comparison will also detect if the lists are of different size, in case the matrices have a different number of rows.
is it scheme?
(define m1 `((1 2 3 4) (4 5 6 6 ) (6 7 8 9)))
(define m2 `((5 4) (3 2) (7 1)))
(define (same-size-matrix? m1 m2) (equal? (map length m1) (map length m2)))
(same-size-matrix? m1 m2) ; => #f
(same-size-matrix? m1 m1) ; => #t
Here is a simple definition of same-size?.
#lang racket
; A MATRIX is a list of ROWs.
; A ROW is a list of numbers.
; In a matrix all rows are of the same length.
(define (row-size list-of-rows)
(length list-of-rows))
(define (column-size matrix)
(define first-row (first matrix))
(length first-row))
(define (same-size? matrix1 matrix2)
(and (= (row-size matrix1) (row-size matrix2))
(= (column-size matrix1) (column-size matrix2))))
As a bonus here is a predicate that test whether an object
is a matrix or not. Compare it to the data definitions.
(define (row? object)
(and (list? object)
(andmap number? object)))
(define (matrix? object)
(and (list? object)
(andmap row? object)
(apply = (map row-size object))))
You need to clarify if you want to check 1) the exact shape of the matrix or 2) the overall 'flattened' length.
what should be the result for (same-size-matrix? '((1 2) (3 4) (5 6)) '((1 2 3) (4 5 6)))?
1) => #f
2) => #t
Óscar López's answer is for 1.
If your requirement is 2, based on Óscar's answer:
(define (same-size-matrix? mtrx1 mtrx2)
(equal? (apply + (map length mtrx1)) (apply + (map length mtrx2))))