Assignment 1: One-Liners
Errata
Problem 2: We say don’t use Array#reverse; but avoid all #reverse methods on core classes (Array#reverse_each, Enumerable#reverse_each, etc.). For example, you will be downgraded for using String#reverse. There are a number of excellent solutions.
Problem 4: you may assume that the sorted order of the values is distinct.
Problem 6: You may assume that the parts of the String before and after the dash are greater than or equal to 0. Numbers only (so no “a..z”).
Problem 9: When we say that the items 1, 5, 10, etc. are the same, we mean that the first three elements of each array are the same.
No solutions require the use of “eval”! Avoid!
No solutions require the use of “tap”! Avoid!
The point of this assignment is to develop your skills at writing concise and “Rubyish” Ruby code. Ruby has large and clever core and standard libraries, as well as syntax that allows for writing short but readable code. Some claim that 10 lines of Java can be expressed in 1 line of Ruby.
We give you a Ruby class with a number of methods — but in the code we hand out, there is no implementation for each method. You have to write the implementation. Each method is preceded with a comment that defines the parameters and return value for the method. There are 10 problems; You must do as many as you can. Each is worth 10 points, totaling 100 points. Some are easy; some are hard.
We’d also like you to invent a Ruby one-liner challenge of your own. In the class we hand out, you’ll see that after the 10 problems, there is an additional method called student_one_liner. At present it has two parameters a and b, but, like many of the one-liners we assign to you, you may have a good one with just 1 parameter. Then over in the test code in test/other/solution_set_test.rb, you should write one or more tests that exercises your one-liner — or simply replace the example method called test_student_one_liner. Also don’t forget to put a comment before the method that “solves” your one-liner that explains what the one-liner is supposed to do. If you write a great one-liner challenge, we will use it in the course in a subsequent year and will credit you. We will take the quality of your one-liner into account should your final score fall on a grade boundary.
It is fair game to consult the Pickaxe (also known as Programming Ruby), Ruby documentation, and other published works and articles on Ruby in print or on the web. It is not fair, however, to use a search engine to find answers. That is, if there’s some struggle to find an example answer, that’s ok because I’d hope you’d learn something along the way: But Googling for the specific answer would not create the neural pathways in your brain.
The easiest way to work through these is to write your code in irb. Once you have a good solution, paste it into the solution set. Indeed, facility with irb is one of the most important things you should be practicing at this stage of the course.
There are some rules regarding your implementation for each method.
- Your implementation must be one line of Ruby code. What is meant by “a single line”? You must supply one statement. You may not use the statement separator (the semi-colon) to separate statements inside the method block. There is an exception to the “single line” rule: You may include one extra statement inside of an iterator block by using the semi-colon. (This proves to be especially important for inject, but is also sometimes useful for collect as well.)
- Unless explicitly permitted by the question, you may not define additional variables. This doesn’t include block parameters — the params inside vertical bars in an expression like
a.map { |e| e*2 } - You may not change the values of the parameters, or elements of the parameters (if any). (For example, if an array [1, 2, 3] is passed in as the parameter a, you may not set a[0] = 2 in the method.) To prevent this, we “freeze” the parameters before we test your methods.
- Avoid regular expressions. Assume that there is a “better” Ruby way to do something than to use a regular expression. Exception: It is very handy to split a String into an array with
s.split(//)(though even this can be done without explicitly giving a regular expression withs.split(''). - Always hand in whatever you have. In other words, if you have had to use extra statements, variables, or regular expressions, still hand it in! Working code, even if not Rubyish and elegant, is still working code and will be recognized as such. The best submissions, though, will observe all of the rules above.
– use those all you want.
The following is NOT an acceptable solution for a couple of reasons: It’s more than one line, and it depends on introducing an extra variable h outside of your single line:
# Not acceptable!
h = Hash.new
h.default=0
a.collect! { |x| h[x] += 1 }
(If you find yourself needing to introduce a variable that “keeps track” of something, review the documentation for Enumerable#inject – Also note that it is fair game to use the new method as needed . . .)
Example:
# Given an Array 'a' of Strings, return a new Array with the same values sorted in reverse # order. def empl_a(a) # your solution end
So, for example, a solution would be like so:
# Given an Array 'a' of Strings, return a new Array with the same values sorted in reverse # order. def empl_a(a) a.reverse end
You must also define a few methods that provide your name, e-mail address, and student id. In their current form they look like this:
def info_first_name "Your first name" end
And must become:
def info_first_name "John" end
To make it easier to check your work, we have provided you with a test framework. To run it, change your directory to test/other/ and run solution_set_test.rb. For example:
jgnmbair:assn1 jgn$ cd test/other jgnmbair:other jgn$ ruby solution_set_test.rb Loaded suite solution_set_test Started ..FFFFFFFFFFFFFF Finished in 0.033543 seconds. 1) Failure: test_prob01_0(StudentSolutionSetTest) [solution_set_test.rb:35:in `check' solution_set_test.rb:19:in `test_prob01_0']: <"ThisIsATestOfTheEmergencyBroadcastSystem"> expected but was <nil>. # MUCH DELETED 16 tests, 16 assertions, 14 failures, 0 errors jgnmbair:other jgn$
Notice the line with “..FFFFFFFFFFFFFF” — the dots signify passed tests. We provide the solution for the first four examples. The rest of the tests are failing because there is no code defined to satisfy the requirements.
Each method is tested with one or more data sets. You can look at the datasets in test/fixtures/test_case_datasets.yml. While you are working, you may want to look at this, and even edit it to add or remove sample data. But keep in mind that we will test with at least this data and possibly more.
We have also added a means to test just ONE problem. If you specify the problem number (01, 02, 03, etc.) after “ruby solution_set_test.rb”, then the tests for that problem only will be run, and we also dump out the input parameters and expected results. Example:
jgnmbair:other jgn$ ruby solution_set_test.rb 05 Loaded suite solution_set_test Started . Problem: 05 Dataset: 0 Parameter(s): a = [25, 10, 5, 1] b = 124 Exepected result: [4, 2, 0, 4] F Problem: 05 Dataset: 1 Parameter(s): a = [25, 10, 5, 1] b = 194 Exepected result: [7, 1, 1, 4] F Finished in 0.009801 seconds. 1) Failure: test_prob05_0(SolutionSetTest) [solution_set_test.rb:59:in `check' solution_set_test.rb:24:in `test_prob05_0']: <[4, 2, 0, 4]> expected but was <nil>. 2) Failure: test_prob05_1(SolutionSetTest) [solution_set_test.rb:59:in `check' solution_set_test.rb:24:in `test_prob05_1']: <[7, 1, 1, 4]> expected but was <nil>. 3 tests, 2 assertions, 2 failures, 0 errors jgnmbair:other jgn$
Checklist for Submission
- Download the code bundle from the downloads page.
- Define the “info” methods providing your first name, last name, e-mail address, and student id number.
- Define your implementations for the 10 methods.
- Include your own one-liner (comment, implementation, and test).
- Zip everything up into an archive with your name in the file name. NOTE: You can use the “rake package” command to do this very neatly.
- One last thing: Please do not post this assignment anywhere or make copies of it.
For the "student_one_liner" problem, do we need to use 2 arguments (a, b), or can we use only one? I do not know if we should follow the example given (using a, b), or if we can come up with just about anything?
Karin,
If you look at the comments that define the problem, you'll see that the operation is defined in terms of two parameters. So you have to use those arguments. Without both arguments, you won't be able to get the result.
Sorry, read that variables!
But in the problem statement above, you said "At present it has two parameters a and b, but, like many of the one-liners we assign to you, you may have a good one with just 1 parameter." The one I submitted has just one parameter.
@Karin
Sorry -- I misread your question.
For your own one-liner, you can use as many parameters as you want: 1 or more.
@Ron Newman
Right, sorry. I misread Karin's question; In my haste I thought she meant one of the assigned problems.
For your own one liner, use at least one parameter.
For Prob 06, can we assume that "String 'a' in the form '1-100'" could also be 'a-c' in which case we should be able to support an output of a..c? Or are we dealing only with integers?
Thanks in advance,
Alex
@Alexander Dawson
Good question. Assume that the start and end are Numeric and that you can send the message to_i to them.
@john
do we need to handle negative numbers e.g. -100-100, -100--50??
as you can see for the second example, makes things a little trickier. Or should we assume that the input is >=0???
@Lateral Punk
No negative numbers.
@john
About comments in the assignment, I added an alternative that I've find better but came up with after discussing it and seing a friend's solution. Just so my TA doesn't think I'm that verbose all the time...
Problem 7 (inserting the comma separators for large numbers)
Is the modulo operator required? I've created what I think is a perfectly good solution with something else. I know it's hinted, but I don't want to lose points for not using it. (I didn't use any regular expressions)
@Alexander Dawson
You don't have to use the modulo operator -- we look forward to reading your solution!
For problem 9, do we need to handle the case of inner arrays that of length 1 or 2? Or can we assume all inner arrays will have at least 3 elements?
@Mark Knell
Assuming that the inner Arrays always have 3 or more elements.
In problem 3, why does the order of the resultant hash entries matter?
@Virginia
I didnt even look at the order of my resultant hash until I saw you asked. My solution passed the given tests, so I figured that was a good start. I wonder if it matters at all. Looking at the description in the solution set and the test data that the solution_set_test uses, I see the array is the same, but the expected results are different. One is ordered, the other is not. My 2 cents.
-peter
@Virginia
I don't think it does matter -- Are you seeing that it does? The test should work no matter what the order of your Hash keys.
@peter
This is right, peter.
Just FYI, { 'one' => 1, 'two' => 2 } == { 'two' => 2, 'one' => 1 }
Virginia, review your Hash key/value pairs. The test would fail if a key/value pair is wrong. In question 3, in the result, each key/value pair should have as key the String value of an element from the input Array, and the value should be the number of times that Array element occurs.
However (and not relevant to problem 3),
{ 'one' => 1, 'two' => 2 }.keys != { 'two' => 2, 'one' => 1 }.keys
{ 'one' => 1, 'two' => 2 }.values != { 'two' => 2, 'one' => 1 }.values
{ 'one' => 1, 'two' => 2 }.to_a != { 'two' => 2, 'one' => 1 }.to_a