CSE341 Final Winter 2007 Name of Student_______________________________________________________________ This is an open-book/open-note exam. Space is provided for your answers. Use the backs of pages if necessary. The exam is divided into eleven questions with the following distribution of points: # Problem Area Points Score ----------------------------------------------------- 1 Scheme Expressions 10 _____ 2 Scheme Programming 10 _____ 3 Scheme Programming 10 _____ 4 Scheme Programming 10 _____ 5 Scheme Programming 10 _____ 6 Scheme Programming 10 _____ 7 Ruby Expressions 8 _____ 8 Ruby Programming 8 _____ 9 Ruby Programming 8 _____ 10 Ruby Programming 8 _____ 11 Ruby Programming 8 _____ ---------------------------------- Total 100 _____ Do not begin work on this exam until instructed to do so. Any student who starts early or who continues to work after time is called will receive a 10 point penalty. Unless otherwise noted, you may use any standard language feature. You may also define helper procedures/methods. For the Scheme questions, you may call any Scheme procedure that is included as a problem on this exam, whether or not you correctly solve that problem. For the Ruby questions, you may call any Ruby method that is included as a problem on this exam, whether or not you correctly solve that problem. 1. (10 points) For each sequence of Scheme expressions below, indicate what value the final expression evaluates to. (2 points) Part A: (define a 2) (define b 5) (define c 10) (let ((b (+ a b)) (c (+ b c))) (+ a b c)) (2 points) Part B: (define a 2) (define b 5) (define c 10) (let* ((b (+ a b)) (c (+ b c))) (+ a b c)) (3 points) Part C: (define a 'b) (define b (cons a '(a b))) (set! a 1) (set-car! (cdr (cdr b)) 2) (list a b) (3 points) Part D: (define a '(1 2)) (define b (cons 4 a)) (define c (append b a)) (set-cdr! a '(3)) (set-car! b 5) (list a b c) 2. (10 points) Define a Scheme procedure prepend that takes a value and a list of lists as arguments and that returns a new list obtained by inserting the given value at the front of each list within the list of lists. For example: > (prepend 'a '((b c) (2 3 4) (9) () (17 x y))) ((a b c) (a 2 3 4) (a 9) (a) (a 17 x y)) Your procedure should not change the list passed as a parameter. Write your solution to prepend below. 3. (10 points) Define a Scheme procedure difference that takes lists lst1 and lst2 as arguments and that returns a new list obtained by removing all values that appear in lst2 from lst1, otherwise preserving order. We saw that Ruby provides this as a basic operation on Array objects (lst1 - lst2). For example: > (difference '(a 1 3 b (a 2) 2 c 19 8 2 b 3) '(a 2)) (1 3 b (a 2) c 19 8 b 3) Your procedure should not change either of the lists passed as parameters. Write your solution to difference below. 4. (10 points) Define a Scheme procedure prefix that takes two lists as arguments and that returns #t if the first list is a prefix of the second and that returns #f otherwise. The first list is considered a prefix of the second if its elements appear at the front of the second list in the same order. The values in the lists might be of any type, not just numbers. For example: > (prefix '(1 8 3) '(1 8 3 17 95)) #t > (prefix '(a b c) '(a b c d e f)) #t > (prefix '(3 9 12) '(3 9 a b c)) #f > (prefix '(3 9 12) '(3 9)) #f By definition, the empty list is considered a prefix of any other list and a list is considered a prefix of itself. Your procedure should not change either of the lists passed as parameters. Write your solution to prefix below. 5. (10 points) Define a Scheme procedure multiples that takes as an argument a list of integers and that returns a new list that indicates a count of the number of multiples each value has in the original list. For example: > (multiples '(9 8 1 2 3 16)) (1 2 6 3 2 1) The value 9 is replaced by 1 because only 1 value in the original list is a multiple of 9 (9 itself). The value 8 is replaced by 2 because there are 2 multiples of 8 (8 and 16). The value 1 is replaced by 6 because there are 6 multiples of 1 (all 6 numbers). The value 2 is replaced by 3 because there are 3 multiples of 2 (8, 2 and 16). And so on. Assume that all values in the list are integers greater than 0. Your procedure should not change the list passed as a parameter. Write your solution to multiples below. 6. (10 points) Define a Scheme procedure choose that takes an integer n and a list of values as arguments and that returns a new list that includes all lists that can be formed by choosing n values from the original list in order. For example: > (choose 2 '(1 2 3 4 5)) ((1 2) (1 3) (1 4) (1 5) (2 3) (2 4) (2 5) (3 4) (3 5) (4 5)) This list includes all possible ways to choose 2 values from the numbers 1 through 5. Notice that values are chosen in the same order in which they appear in the original list. You may assume that there are no duplicates in the original list and you may list the solutions in any order. For example, (1 2) is a solution while (2 1) is not (because the order has to match the order in the original list), but the solution (1 2) does not have to appear before the solution (1 3) in the answer, which means that the solution given above is just one possible right answer. Your procedure should work for lists of any type, as in: > (choose 0 '(a b c)) (()) > (choose 1 '(a b c)) ((a) (b) (c)) > (choose 2 '(a b c)) ((a b) (a c) (b c)) > (choose 3 '(a b c)) ((a b c)) > (choose 4 '(a b c)) () Notice that there is exactly one way to choose 0 values from a list (the empty list) and that there are no ways to choose n values from a list of length less than n. Your procedure should call the error procedure if the integer is less than 0. Your solution has to avoid gross inefficiency. For example, it can't require time greater than O(m^n) where m is the length of the list and n is the number of items to choose. Your procedure should not change the list passed as a parameter. Write your solution to choose below. 7. (8 points) Assuming that the following variables have been defined: x = [3, 8, 9, 7, 4, 5] y = 2..4 sum = 0 (2 points) Part A: What output is produced by the following code? x.each {|n| puts 2 * n - 1} (2 points) Part B: What output is produced by the following code? y.each {|n| puts n * x[n]} (2 points) Part C: What output is produced by the following code? sum = 0 y.each do |n| sum += n puts n end puts sum (2 points) Part D: What value is returned by the following expression? x.map {|n| [n, n]} 8. (8 points) Define a Ruby method match(lst1, lst2) that takes two arrays as arguments and that returns an array containing the values in order from the two arrays that match. A value is considered to be a match if it appears in both arrays in the same position. For example: >> match([3, 8, 19, 7, 4], [19, 8, 4, 7, 4, 12, 13]) => [8, 7, 4] >> match(["t", "e", "m", "p", "l", "e"], ["t", "a", "m", "p", "e", "r"]) => ["t", "m", "p"] Notice that one array can be longer than the other. Your method should not change either of the arrays that are passed as parameters. Write your solution to match below. 9. (8 points) Define a Ruby method unique(lst) that takes an array as an argument and that returns a new array containing the values from lst minus any duplicates. The new array should have the values in the same relative order as their first occurrence in the original array. In other words, a value i should appear before a value j in the result if and only if the first occurrence of i appears before the first occurrence of j in the original array. For example: >> unique([14, 8, 12, 1, 11, 10, 4, 9, 1, 2, 5, 2, 4, 12, 12]) => [14, 8, 12, 1, 11, 10, 4, 9, 2, 5] >> unique(["m", "i", "s", "s", "i", "s", "s", "i", "p", "p", "i"]) => ["m", "i", "s", "p"] This is such a useful operation that Ruby includes it in the Array class as a method called uniq with a mutator uniq!. You may not call these built-in versions to solve the problem. Your method should not change the array passed as a parameter. Write your solution to unique below. 10. (8 points) Define a Ruby method split(lst,n) that takes an array lst and an integer n as arguments and that returns an array of n arrays containing the values from the original array. The first n values from the original array should become the first values, in order, in the n arrays of the new array. The second set of n values from the original array should become the second values, in order, in the n arrays of the new array. And so on. For example: >> split([3, 4, 5, 6, 10, 13, 4, 9, 8], 3) => [[3, 6, 4], [4, 10, 9], [5, 13, 8]] Notice that the first 3 values (3, 4, 5) are the first values in the three arrays in the result and they appear in order (3 is included in the first array, 4 is included in the second array, 5 is included in the third array). Similarly, the second group of 3 values (6, 10, 13) are the second values of the three arrays, also in order (6 in the first array, 10 in the second, 13 in the third). If the last group of numbers does not have n values, then your method should add as many values as it can to the appropriate arrays. For example: >> split([3, 4, 5, 6, 10, 13, 4, 9, 8, 7], 4) => [[3, 10, 8], [4, 13, 7], [5, 4], [6, 9]] The final group of values has just two values (8, 7), so only the first two of the arrays in the result have a third value. It is possible to get an empty array in the result, as in: >> split(["hello", "world", "today"], 5) => [["hello"], ["world"], ["today"], [], []] You may assume that the integer passed to your method is greater than 0. Your method should not change the array passed as a parameter. Write your solution to split below. 11. (8 points). Extend the Array class to have a new method called values that generates pairs of values that each have a value from the array and the number of occurrences of that value. Each different value from the array should be generated just once and should be generated in the order in which it appears in the array. A client would use a block with two parameters to access the pairs generated by your method. This code, for example: x = [9, 7, 9, 5, 0, 6, 5, 12, 5, 9, 11, 2, 3, 0, 0, 9, 3, 10, 3, 6] x.values {|v, count| print v, " occurs ", count, " times\n"} should produce the following output: 9 occurs 4 times 7 occurs 1 times 5 occurs 3 times 0 occurs 3 times 6 occurs 2 times 12 occurs 1 times 11 occurs 1 times 2 occurs 1 times 3 occurs 3 times 10 occurs 1 times Your method should return the number of values generated (10 in the example above). Your method should not change the array. Write your solution to values below.
Stuart Reges
Last modified: Thu Mar 22 15:10:11 PDT 2007