#songs = [{artist: 'Artist', title: 'Title String', playback: '04:30'} etc]
def convert_to_secs
a = str.split(':').map!{|x| x.to_i}
return (a[0] * 60) + a[1]
end
def longest_possible(playback)
#songs.select do |hsh|
x = hsh[:playback].convert_to_secs
end
return x
end
When trying to call convert_to_seconds inside longest_possible I get the following error:
longest_possible.rb:5:in `block in longest_possible': private method
`convert_to_secs' called for "04:30":String (NoMethodError)
from longest_possible.rb:4:in `select'
from longest_possible.rb:4:in `longest_possible'
from longest_possible.rb:15:in `<main>'
I'm not sure if my problem can be solved with scope operators, or whether this requires something with classes (not something I have touched upon yet.) Could you please point me in the right direction?
PS, ignore the functionality of the second function, i've not gotten around to making that one yet, just posted for example.
The main problem seems to be that you call the method using the string as the receiver. It then tries to find the method convert_to_secs among the methods predefined for strings and doesn't find it. Instead, you should pass hsh[:playback] as an argument. So your code should look like this:
def convert_to_secs(str) # Note the argument str introduced here
# You don't need map! here. Normal map suffices.
a = str.split(':').map {|x| x.to_i}
# In Ruby, you can leave away the return keyword at the end of methods.
(a[0] * 60) + a[1]
end
def longest_possible(playback)
#songs.select do |hsh|
x = convert_to_secs(hsh[:playback])
end
return x
end
Related
I am doing this exercise:
To do this exercise, you will probably have to use return self. If the method returns itself (an instance of itself), we can chain methods.
Develop a ruby class called MathDojo that has the following functions: add, subtract. Have these 2 functions take at least 1 parameter. MathDojo.new.add(2).add(2, 5).subtract(3, 2) should perform 0+2+(2+5)-(3+2) and return 4.
I have this code:
class MathDojo
def initialize
#sum = 0
end
def add(*numbers)
numbers.inject(#sum) { |sum, number| sum + number }
self
end
def subtract(*numbers)
numbers.inject(#sum) { |sum, number| sum - number }
self
end
end
Right now, my code returns:
MathDojo.new.add(2).add(2, 5).subtract(3, 2)
# => #<MathDojo:0x0000000160b0c0>
How do I return the instance variable of an object instead of the object itself? When I remove the return to self, the methods no longer chain, although I am able to make a single method call:
MathDojo.new.subtract(2,3)
# => -5
How do I modify my code so the chaining works as expected?
Self-solved, had to edit, because the downvotes on my question put me under the reputation needed to answer my own question. My apologies.
I needed to flatten the array before injecting numbers into the array. Then added attr_accessor to collect the sum for use outside the class. I also changed the implied return of self to read:
return self
I modified the code by entering the following, as shown by jbh's answer:
attr_accessor :sum
before my initialize method
Then I modified the add and subtract methods to include calling flatten:
#sum = numbers.flatten.inject(#sum) { |sum, number| sum + number }
#sum = numbers.flatten.inject(#sum) { |sum, number| sum - number }
then as jbh also showed I added .sum to my chained methods:
puts math1 = MathDojo.new.add(2).add(2, 5).subtract(3, 2).sum
One more thing, people talk about how curmudgeony the problem solver-people on stackoverflow can be and today I experienced that. I clearly mentioned I was new to Ruby (I should have stated it's only my 2nd day) and I had to have my reputation voted down 2 points because they didn't like the format of my question, all that needed to be done was the edit.
You cannot know when a method is called if there will be a chain call after it. So you cannot choose if you should return self or the sum value.
Simple answer for that, create a sum method that should be called at the end of your chain call
class MathDojo
attr_reader :sum
end
puts MathDojo.new.add(2).add(2, 5).subtract(3, 2).sum
Being new to Ruby, I'm having trouble explaining to myself the behavior around method definitions within Ruby.
The example is noted below...
class Foo
def do_something(action)
action.inspect
end
def do_something_else=action
action.inspect
end
end
?> f.do_something("drive")
=> "\"drive\""
?> f.do_something_else=("drive")
=> "drive"
The first example is self explanatory. What Im trying to understand is the behavior of the second example. Other than what looks to be one producing a string literal and the other is not, what is actually happening? Why would I use one over the other?
Generally, do_something is a getter, and do_something= is a setter.
class Foo
attr_accessor :bar
end
is equivalent to
class Foo
def bar
#bar
end
def bar=(value)
#bar = value
end
end
To answer your question about the difference in behavior, methods that end in = always return the right hand side of the expression. In this case returning action, not action.inspect.
class Foo
def do_something=(action)
"stop"
end
end
?> f = Foo.new
?> f.do_something=("drive")
=> "drive"
Both of your methods are actually being defined and called as methods. Quite a lot of things in Ruby can be defined as methods, even the operators such as +, -, * and /. Ruby allows methods to have three special notational suffixes. I made that phrase up all by myself. What I mean by notational suffixes is that the thing on the end of the method will indicate how that method is supposed to work.
Bang!
The first notational suffix is !. This indicates that the method is supposed to be destructive, meaning that it modifies the object that it's called on. Compare the output of these two scripts:
a = [1, 2, 3]
a.map { |x| x * x }
a
And:
a = [1, 2, 3]
a.map! { |x| x * x }
a
There's a one character difference between the two scripts, but they operate differently! The first one will still go through each element in the array and perform the operation inside the block, but the object in a will still be the same [1,2,3] that you started with.
In the second example, however, the a at the end will instead be [1, 4, 9] because map! modified the object in place!
Query
The second notational suffix is ?, and that indicates that a method is used to query an object about something, and means that the method is supposed to return true, false or in some extreme circumstances, nil.
Now, note that the method doesn't have to return true or false... it's just that it'd be very nice if it did that!
Proof:
def a?
true
end
def b?
"moo"
end
Calling a? will return true, and calling b? will return "moo". So there, that's query methods. The methods that should return true or false but sometimes can return other things because some developers don't like other developers.
Setters!
NOW we get to the meat of your (paraphrased) question: what does = mean on the end of a method?
That usually indicates that a method is going to set a particular value, as Erik already outlined before I finished typing this essay of an answer.
However, it may not set one, just like the query methods may not return true or false. It's just convention.
You can call that setter method like this also:
foo.something_else="value"
Or (my favourite):
foo.something_else = "value"
In theory, you can actually ignore the passed in value, just like you can completely ignore any arguments passed into any method:
def foo?(*args)
"moo"
end
>> foo?(:please, :oh, :please, :why, :"won't", :you, :use, :these, :arguments, :i, :got, :just, :for, :you, :question_mark?)
=> "moo"
Ruby supports all three syntaxes for setter methods, although it's very rare to see the one you used!
Well, I hope this answer's been roughly educational and that you understand more things about Ruby now. Enjoy!
You cannot define a return value for assignment methods. The return value is always the same as the value passed in, so that assignment chains (x = y = z = 3) will always work.
Typically, you would omit the brackets when you invoke the method, so that it behaves like a property:
my_value = f.do_something= "drive"
def do_something_else=action
action.inspect
end
This defines a setter method, so do_something_else appears as though we are initializing a attribute. So the value initialized is directly passed,
Hey I have a problem with my method that calculates the covariance of two arrays.
There is always the error:
undefined method 'kovarianz' for main:Object
Here is my Code:
rohstoff1 = "Eisen"
rohstoff2 = "Neodym"
daten_rohstoff1 = [1,2,3,4,5,6]
daten_rohstoff2 = [10,11,15,16,17,18]
module Enumerable
def mean
m = self.reduce(:+) / self.length.to_f
return m
end
def covariance (dat1,dat2)
kovar = dat1.inject(0) { |sum, x| sum + (x-dat1.mean) } *
dat2.inject(0) { |sum, x, i| sum + (x-dat2.mean) } / dat1.length.to_f
return kovar
end
end
puts "Kovarianz von #{rohstoff1} und #{rohstoff2} = " +
covariance(daten_rohstoff1,daten_rohstoff2)
There are two things wrong with what you're doing. First, you've defined an Enumerable instance method, not a class method. You won't pass in the array you are operating on but, rather, you will call covariance directly on the array:
daten_rohstoff1.covariance daten_rohstoff2
You should therefore define the method to take only one argument, namely the second array.
Second, and as mentioned before, you've defined a method covariance but are trying to call kovarianz. This, obviously, will not work.
The method name is called covariance but you call kovarianz in the last line. Change one or the other and you should be golden.
Well, the primary issue here being that you called kovarianz, as opposed to covariance, but the fact that the code is also embedded in a module means you have to call it like so:
Enumerable::covariance(daten_rohstoff1,daten_rohstoff2)
Hope this helped.
It is said that when we have a class Point and knows how to perform point * 3 like the following:
class Point
def initialize(x,y)
#x, #y = x, y
end
def *(c)
Point.new(#x * c, #y * c)
end
end
point = Point.new(1,2)
p point
p point * 3
Output:
#<Point:0x336094 #x=1, #y=2>
#<Point:0x335fa4 #x=3, #y=6>
but then,
3 * point
is not understood:
Point can't be coerced into Fixnum (TypeError)
So we need to further define an instance method coerce:
class Point
def coerce(something)
[self, something]
end
end
p 3 * point
Output:
#<Point:0x3c45a88 #x=3, #y=6>
So it is said that 3 * point is the same as 3.*(point). That is, the instance method * takes an argument point and invoke on the object 3.
Now, since this method * doesn't know how to multiply a point, so
point.coerce(3)
will be called, and get back an array:
[point, 3]
and then * is once again applied to it, is that true?
Now, this is understood and we now have a new Point object, as performed by the instance method * of the Point class.
The question is:
Who invokes point.coerce(3)? Is it Ruby automatically, or is it some code inside of * method of Fixnum by catching an exception? Or is it by case statement that when it doesn't know one of the known types, then call coerce?
Does coerce always need to return an array of 2 elements? Can it be no array? Or can it be an array of 3 elements?
And is the rule that, the original operator (or method) * will then be invoked on element 0, with the argument of element 1? (Element 0 and element 1 are the two elements in that array returned by coerce.) Who does it? Is it done by Ruby or is it done by code in Fixnum? If it is done by code in Fixnum, then it is a "convention" that everybody follows when doing a coercion?
So could it be the code in * of Fixnum doing something like this:
class Fixnum
def *(something)
if (something.is_a? ...)
else if ... # other type / class
else if ... # other type / class
else
# it is not a type / class I know
array = something.coerce(self)
return array[0].*(array[1]) # or just return array[0] * array[1]
end
end
end
So it is really hard to add something to Fixnum's instance method coerce? It already has a lot of code in it and we can't just add a few lines to enhance it (but will we ever want to?)
The coerce in the Point class is quite generic and it works with * or + because they are transitive. What if it is not transitive, such as if we define Point minus Fixnum to be:
point = Point.new(100,100)
point - 20 #=> (80,80)
20 - point #=> (-80,-80)
Short answer: check out how Matrix is doing it.
The idea is that coerce returns [equivalent_something, equivalent_self], where equivalent_something is an object basically equivalent to something but that knows how to do operations on your Point class. In the Matrix lib, we construct a Matrix::Scalar from any Numeric object, and that class knows how to perform operations on Matrix and Vector.
To address your points:
Yes, it is Ruby directly (check calls to rb_num_coerce_bin in the source), although your own types should do too if you want your code to be extensible by others. For example if your Point#* is passed an argument it doesn't recognize, you would ask that argument to coerce itself to a Point by calling arg.coerce(self).
Yes, it has to be an Array of 2 elements, such that b_equiv, a_equiv = a.coerce(b)
Yes. Ruby does it for builtin types, and you should too on your own custom types if you want to be extensible:
def *(arg)
if (arg is not recognized)
self_equiv, arg_equiv = arg.coerce(self)
self_equiv * arg_equiv
end
end
The idea is that you shouldn't modify Fixnum#*. If it doesn't know what to do, for example because the argument is a Point, then it will ask you by calling Point#coerce.
Transitivity (or actually commutativity) is not necessary, because the operator is always called in the right order. It's only the call to coerce which temporarily reverts the received and the argument. There is no builtin mechanism that insures commutativity of operators like +, ==, etc...
If someone can come up with a terse, precise and clear description to improve the official documentation, leave a comment!
I find myself often writing code along this pattern when dealing with commutativity:
class Foo
def initiate(some_state)
#...
end
def /(n)
# code that handles Foo/n
end
def *(n)
# code that handles Foo * n
end
def coerce(n)
[ReverseFoo.new(some_state),n]
end
end
class ReverseFoo < Foo
def /(n)
# code that handles n/Foo
end
# * commutes, and can be inherited from Foo
end
In Ruby, is it possible to pass by reference a parameter with value-type semantics (e.g. a Fixnum)?
I'm looking for something similar to C#'s 'ref' keyword.
Example:
def func(x)
x += 1
end
a = 5
func(a) #this should be something like func(ref a)
puts a #should read '6'
Btw. I know I could just use:
a = func(a)
You can accomplish this by explicitly passing in the current binding:
def func(x, bdg)
eval "#{x} += 1", bdg
end
a = 5
func(:a, binding)
puts a # => 6
Ruby doesn't support "pass by reference" at all. Everything is an object and the references to those objects are always passed by value. Actually, in your example you are passing a copy of the reference to the Fixnum Object by value.
The problem with the your code is, that x += 1 doesn't modify the passed Fixnum Object but instead creates a completely new and independent object.
I think, Java programmers would call Fixnum objects immutable.
In Ruby you can't pass parameters by reference. For your example, you would have to return the new value and assign it to the variable a or create a new class that contains the value and pass an instance of this class around. Example:
class Container
attr_accessor :value
def initialize value
#value = value
end
end
def func(x)
x.value += 1
end
a = Container.new(5)
func(a)
puts a.value
You can try following trick:
def func(x)
x[0] += 1
end
a = [5]
func(a) #this should be something like func(ref a)
puts a[0] #should read '6'
http://ruby-doc.org/core-2.1.5/Fixnum.html
Fixnum objects have immediate value. This means that when they are assigned or
passed as parameters, the actual object is passed, rather than a reference to
that object.
Also Ruby is pass by value.
However, it seems that composite objects, like hashes, are passed by reference:
fp = {}
def changeit(par)
par[:abc] = 'cde'
end
changeit(fp)
p fp
gives
{:abc=>"cde"}