I am just wondering if .length() is just an alias of .length because they return the same result:
[38] pry(main)> temp = [1,2,3]
=> [1, 2, 3]
[40] pry(main)> temp.length
=> 3
[41] pry(main)> temp.length()
=> 3
There is no difference. In Ruby, you can omit the parentheses around arguments in many cases.
temp.length
temp.length()
are identical. The same is true for
temp.push(4)
temp.push 4
In Ruby, when you define or call (execute, use) a method,
you can omit the parentheses.
So these lines mean exactly the same:
temp.length
temp.length()
http://ruby-for-beginners.rubymonstas.org/bonus/parentheses.html
Just an addition to these answers.
You can also omit parentheses on method definitions as well, not only method calls.
For example:
def length
1
end
def length()
2
end
http://ruby-for-beginners.rubymonstas.org/bonus/parentheses.html
Related
I need Ruby method to convert an array of strings into a Hash where each key is a string and each value is the 1-indexed index of the string in the original array.
hashify(%w(a b c))
# should return
{'a' => 1, 'b' => 2, 'c' => 3}
Even though I think I'm helping someone do their homework, I can't resist taking a golf swing, because Ruby is awesome:
%w(a b c).each.with_index(1).to_h
Also, defining "hashify" is VERY un-Ruby-like. I'd suggest alternatives, but it's probably a homework assignment anyways and you don't seem to want to learn it.
def hashify(array)
array.each.with_index(1).to_h
end
hashify(%w(a b c))
#=> { "a" => 1, "b" => 2, "c" => 3 }
There are (clearly) multiple ways you could achieve your goal in Ruby.
If you consider the expression %w(a b c).map.with_index(1).to_h, you can see that it is a matter of stringing together a few methods provided to us by the Enumerable class.
By first sending the :map message to the array, we receive back an Enumerator, which provides us the handy :with_index method. As you can see in the docs, with_index accepts an offset in an argument, so offsetting your indices by 1 is as simple as passing 1 as your argument to :with_index.
Finally, we call :to_h on the enumerator to receive the desired hash.
# fore!
def hashify(array)
array.map.with_index(1).to_h
end
> hashify %w(a b c)
=> {"a"=>1, "b"=>2, "c"=>3}
Try this, this will add a method to_hash_one_indexed to the Array class.
class Array
def to_hash_one_indexed
map.with_index(1).to_h
end
end
Then to call it:
%w(a b c).to_hash_one_indexed
#=> {"a"=>1, "b"=>2, "c"=>3}
I'm having trouble understanding exactly how much state a ruby enumerable keeps.
I know some python, so I was expecting that after I take an item from an enumerable, it's gone and the next item will be returned as I take another item.
Strangely, this does happen when I use next but not when I use anything like take of first.
Here's an example:
a = [1,2,3].to_enum
# => #<Enumerator: [1, 2, 3]:each>
a.take(2)
# => [1, 2]
a.next
# => 1
a.next
# => 2
a.take(2)
# => [1, 2]
a.next
# => 3
a.next
# StopIteration: iteration reached an end
# from (irb):58:in `next'
# from (irb):58
# from /usr/bin/irb:12:in `<main>'
a.take(2)
# => [1, 2]
It seems like the enumerable keeps state between next calls, but resets before each take call?
It may be a little confusing, but it's important to note that in Ruby there is the Enumerator class and the Enumerable module.
The Enumerator class includes Enumerable (like most of enumerable objects such as Array, Hash, etc.
The next method is provided as part of the Enumerator, which indeed has an internal state. You can consider an Enumerator very close to the concept of Iterator exposed by other languages.
When you instantiate the Enumerator, the internal pointer points to the first item in the collection.
2.1.5 :021 > a = [1,2,3].to_enum
=> #<Enumerator: [1, 2, 3]:each>
2.1.5 :022 > a.next
=> 1
2.1.5 :023 > a.next
=> 2
This is not the only purpose of the Enumerator (otherwise it would probably be called Iterator). However, this is one of the documented feature.
An Enumerator can also be used as an external iterator. For example, #next returns the next value of the iterator or raises StopIteration if the Enumerator is at the end.
e = [1,2,3].each # returns an enumerator object.
puts e.next # => 1
puts e.next # => 2
puts e.next # => 3
puts e.next # raises StopIteration
But as I said before, the Enumerator class includes Enumerable. It means every instance of an Enumerator exposes the Enumerable methods that are designed to work on a collection. In this case, the collection is the one the Enumerator is wrapped on.
take is a generic Enumerable method. It is designed to return the first N elements from enum. It's important to note that enum is referring to any generic class that includes Enumerable, not to the Enumerator. Therefore, take(2) will returns the first two elements of the collection, regardless the position of the pointer inside the Enumerator instance.
Let me show you a practical example. I can create a custom class, and implement Enumerable.
class Example
include Enumerable
def initialize(array)
#array = array
end
def each(*args, &block)
#array.each(*args, &block)
end
end
I can mix Enumerable, and as long as I provide an implementation for each I get all the other methods for free, including take.
e = Example.new([1, 2, 3])
=> #<Example:0x007fa9529be760 #array=[1, 2, 3]>
e.take(2)
=> [1, 2]
As expected, take returns the first 2 elements. take ignores anything else of my implementation, exactly as in Enumerable, including states or pointers.
Per the documentation, Enumerable#take returns first n elements from the Enumerator, not the next n elements from the cursor. Only the methods from Enumerator are going to operate on that internal cursor; the Enumerable mix-in is just a collection of methods for enumerating which don't necessarily share cursors.
If you wanted, you could implement Enumerator#take to do what you expect:
class Enumerator
def take(n = 1)
n.times.map { self.next }
end
end
Had some weird results when redefining the unary + operator in Ruby on the Fixnum class. Not exactly sure why things are happening the way they are (specifically line 009).
irb:003> class Fixnum
irb:004> def +# #define unary +
irb:005> 15
irb:006> end
irb:007> end
=> nil
irb:008> 2
=> 2
irb:009> +2
=> 2
irb:010> +(2)
=> 15
irb:011> ++2
=> 15
I suspect you're seeing a side effect of the parser's behavior in how it interprets numeric literals.
If we create our own class:
class C
def +#
11
end
end
and then look at some things:
> c = C.new
> +c
=> 11
> ++c
=> 11
That's exactly what we expect to happen. If we use your Fixnum unary + override and a Fixnum variable:
> n = 23
> +n
=> 15
> ++n
=> 15
then again we see what you're expecting. In both cases, we see the result of calling the +# method on a non-literal.
But when we look at +6 with your operator in place:
> +6
=> 6
the +# method is not called. Similarly if we override -#:
class Fixnum
def -#
'pancakes'
end
end
and see what it does:
> -42
=> 42
So what's going on here? Well, Ruby is seeing +6 and -42 not as 6.send(:+#) and 42.send(:-#) method calls but as single literals for positive six and negative forty-two.
If you start adding parentheses, +(6) and -(42), then Ruby sees non-literal expressions and ends up calling the unary methods. Similarly when you double the unary operators.
This answer adds additional details to mu's answer.
Just learned about ruby's Ripper class, and it shows what's happening pretty clearly:
require 'ripper'
p Ripper.sexp('2') # => [:program, [[:#int, "2", [1, 0]]]]
p Ripper.sexp('+2') # => [:program, [[:#int, "+2", [1, 0]]]]
p Ripper.sexp('+(2)') # => [:program, [[:unary, :+#, [:paren, [[:#int, "2", [1, 2]]]]]]]
p Ripper.sexp('++2') # => [:program, [[:unary, :+#, [:#int, "+2", [1, 1]]]]]
It seems that the arguments are copied when using the splat operator to pass arguments to a block by reference.
I have this:
def method
a = [1,2,3]
yield(*a)
p a
end
method {|x,y,z| z = 0}
#=> this puts and returns [1, 2, 3] (didn't modified the third argument)
How can I pass these arguments by reference? It seems to work if I pass the array directly, but the splat operator would be much more practical, intuitive and maintainable here.
In Ruby when you write x = value you are creating a new local variable x whether it existed previously or not (if it existed the name is simply rebound and the original value remains untouched). So you won't be able to change a variable in-place this way.
Integers are immutable. So if you send an integer there is no way you can change its value. Note that you can change mutable objects (strings, hashes, arrays, ...):
def method
a = [1, 2, "hello"]
yield(*a)
p a
end
method { |x,y,z| z[1] = 'u' }
# [1, 2, "hullo"]
Note: I've tried to answer your question, now my opinion: updating arguments in methods or blocks leads to buggy code (you have no referential transparency anymore). Return the new value and let the caller update the variable itself if so inclined.
The problem here is the = sign. It makes the local variable z be assigned to another object.
Take this example with strings:
def method
a = ['a', 'b', 'c']
yield(*a)
p a
end
method { |x,y,z| z.upcase! } # => ["a", "b", "C"]
This clearly shows that z is the same as the third object of the array.
Another point here is your example is numeric. Fixnums have fixed ids; so, you can't change the number while maintaining the same object id. To change Fixnums, you must use = to assign a new number to the variable, instead of self-changing methods like inc! (such methods can't exist on Fixnums).
Yes... Array contains links for objects. In your code when you use yield(*a) then in block you works with variables which point to objects which were in array. Now look for code sample:
daz#daz-pc:~/projects/experiments$ irb
irb(main):001:0> a = 1
=> 1
irb(main):002:0> a.object_id
=> 3
irb(main):003:0> a = 2
=> 2
irb(main):004:0> a.object_id
=> 5
So in block you don't change old object, you just create another object and set it to the variable. But the array contain link to the old object.
Look at the debugging stuff:
def m
a = [1, 2]
p a[0].object_id
yield(*a)
p a[0].object_id
end
m { |a, b| p a.object_id; a = 0; p a.object_id }
Output:
3
3
1
3
How can I pass these arguments by reference?
You can't pass arguments by reference in Ruby. Ruby is pass-by-value. Always. No exceptions, no ifs, no buts.
It seems to work if I pass the array directly
I highly doubt that. You simply cannot pass arguments by reference in Ruby. Period.
NOTE: mischa's splat on GitHub has lots of cool interactive examples of * in action.
By googling, I found that one way to iterate over a range of numbers in Ruby (your classic C-style for loop)
for (i = first; i <= last; i++) {
whatever(i);
}
is to do something like this
[*first..last].each do |i|
whatever i
end
But what exactly is going on with that [*first..last] syntax? I played around with irb and I see this:
ruby-1.9.2-p180 :001 > 0..5
=> 0..5
ruby-1.9.2-p180 :002 > [0..5]
=> [0..5]
ruby-1.9.2-p180 :003 > [*0..5]
=> [0, 1, 2, 3, 4, 5]
ruby-1.9.2-p180 :004 > *0..5
SyntaxError: (irb):4: syntax error, unexpected tDOT2, expecting tCOLON2 or '[' or '.'
*0..5
^
Everything I've read online discusses the unary asterisk as being useful for expanding and collapsing arguments passed to a method, useful for variable length argument lists
def foo(*bar)
bar
end
foo 'tater' # => ["tater"]
foo 'tater', 'tot' # => ["tater", "tot"]
and I get that, but I don't see how it applies to the expansion being done in my block example above.
To be clear, I know that The Ruby Way is to iterate over an array or collection, not to use the array length and iterate with an integer index. However, in this example, I really am dealing with a list of integers. :)
[*1..10]
is the same thing as
(1..10).to_a # call the "to array" method
Instances of the Array class you have created implement Enumerable so your loop works. On classes that define a to_a method, you can use the splat operator syntax with brackets. Splat does a lot more than just call #to_a though, and would be worth a Google search on its own.
Now, in your case, the Range class itself is already an Enumerable so you could just do:
(first..last).each do |v|
...
end
[first..last] is an array containing only 1 range object. [*first..last] is an array containing the elements of that range having been sent in as an argument list. * works in the context of an argument list.
It is called a splat operator. If you use it within certain positions like an argument position or an array, it will expand into its elements:
a = [1]
[*a, 3] # => [1, 3]
b = [1, 2]
[*b, 3] # => [1, 2, 3]
You can't use it bare or in ranges:
*a..3 # => error.
(*a..3) # => error.
When you have something that is not an array, it returns itself:
a = 1
[*a, 3] # => [1, 3]