I'm fairly new to ruby and I'm a bit confused by what the map! syntax does. I see the following line on the codebase
b.map(&:values).uniq!.map!
b.map(&:values).uniq! gives me the following output:
[["us"],
["au"],
["fr"],
["mx"],
["ad",
"ae",
"af",
"al",
"am",
"ao",
"aq"]]
When I add a .map! to the end of b.map(&:values).uniq! I get #<Enumerator: ...>. I'm not really sure what is happening. If anyone could explain to me what is going on that would be very helpful.
From the documentation:
Invokes the given block once for each element of self, replacing the element with the value returned by the block.
See also Enumerable#collect.
If no block is given, an Enumerator is returned instead.
This means that if you have used map! with a block - the array would have replaced all its elements with the return value of the block:
b.map(&:values).uniq!.map!(&:first)
# => ["us", "au", "fr", "mx", "ad"]
Since you did not add a block, you got an Enumerator, which is like a delayed action cursor, where you can add your block later on:
enum = b.map(&:values).uniq!.map!
enum.each(&:first)
# => ["us", "au", "fr", "mx", "ad"]
Related
Hi how can I access a specific value in ruby hash, for example how can i get "colder" inside jupiter
planets= {
"jupiter" => ["brown", "big" , "colder"]
"mars" => ["red", "small", "cold"]
};
Focus on Intent
There's definitely more than one way to do this, so the key is to focus less in the result (although getting the right result is important) and more on effectively expressing your intent with the code. All of the examples provided below (and others besides) will give you the right result, but the approach and semantics are all slightly different. Always pick the approach that most closely matches what you're trying to say.
Fix Your Hash
Before doing anything else, fix your invalid hash. For example:
planets = {
"jupiter" => ["brown", "big", "colder"],
"mars" => ["red", "small", "cold"],
}
Positional Selection
Select your key, then the last element. Examples include:
planets['jupiter'][2]
#=> "colder"
planets['jupiter'][-1]
#=> "colder"
planets['jupiter'].last
#=> "colder"
Content-Based Selection
If you don't know which element you want to select from the nested array, you'll need to use some form of matching to find it. Examples can include:
planets['jupiter'].grep(/colder/).pop
#=> "colder"
planets['jupiter'].grep(/colder/).first
#=> "colder"
planets['jupiter'].grep(/colder/)[0]
#=> "colder"
planets['jupiter'].select { _1.match? /colder/ }.pop
#=> "colder"
I am new to ruby and working through a tutorial but am not sure what this line of code means:
[movie, version_number].any?(&:nil?)
From my research, Array.any? returns true if any of the elements of the array are not false or nil. And &:nil? means to call to_proc() on the symbol :nil? i.e. :nil?.to_proc so the statement is equivalent to
[movie, version_number].any?(:nil?.to_proc)
which is equivalent to
[movie, version_number].any?{|item| item.nil?}
Further, any? Passes each element of the collection (in this case, Array) to the {|item| item.nil?} block.
When you put them together, does the line of code mean, call nil? on each element in the Array before calling .any? on the array, i.e. is it equivalent to:
[movie.nil?, version_number.nil?].any?
Or, in plain English, are any of movie or version_number equivalent to nil?
From Symbol#to_proc documentation:
Returns a Proc object which respond to the given method by sym.
(1..3).collect(&:to_s) #=> ["1", "2", "3"]
So in your case this is effectively the same as writing:
[movie, version_number].any?{|item| item.nil? }
any? expects a block[1] to be passed, which will be evaluated for each item, and will return true if the block evaluates to true for any of the members.
The to_proc method on Symbol is basically a convenience shortcut, when you just want to call a single method on the item passed to the block. As in the example above, this leads to shorter code than explicitly defining the block.
[1] Refer this article on blocks, procs and lambdas in ruby
As the anonymous block and hash block looks like approximately same. I was doing kind of playing with it. And doing do I reached to some serious observations as below:
{}.class
#=> Hash
Okay,It's cool. empty block is considered as Hash.
print{}.class
#=> NilClass
puts {}.class
#=> NilClass
Now why the above code showing the same as NilClass,but the below code shows the Hash again ?
puts ({}.class)
#Hash
#=> nil
print({}.class)
#Hash=> nil
Could anyone help me here to understand that what's going one above?
I completely disagree with the point of #Lindydancer
How would you explain the below lines:
print {}.class
#NilClass
print [].class
#Array=> nil
print (1..2).class
#Range=> nil
Why not the same with the below print [].class and print (1..2).class?
EDIT
When ambiguity happens with local variable and method call, Ruby throws an error about the fact as below :
name
#NameError: undefined local variable or method `name' for main:Object
# from (irb):1
# from C:/Ruby193/bin/irb:12:in `<main>'
Now not the same happens with {} (as there is also an ambiguity between empty code block or Hash block). As IRB also here not sure if it's a empty block or Hash. Then why the error didn't throw up when IRB encountered print {}.class or {}.class?
The precedence rules of ruby makes print{}.class interpreted as (print{}).class. As print apparently returns a nil the class method returns #NilClass.
EDIT: As been discussed on other answers and in the updates to the question, print{} it of course interpreted as calling print with a block, not a hash. However, this is still about precedence as {} binds stronger than [] and (1..2) (and stronger than do ... end for that matter).
{} in this case is recognized as block passed to print, while [] unambiguously means empty array.
print {}.class # => NilClass
print do;end.class # => NilClass
You are running into some nuances of Ruby, where characters mean different things depending on context. How the source code is interpreted follows rules, one of which is that {} is a closure block if it follows a method call, and otherwise a Hash constructor.
It's common throughout the language to see characters mean different things depending on context or position within the statement.
Examples:
Parens () used for method call or for precedence
print(1..5).class => NilClass
print (1..5).class => Range <returns nil>
Square brackets [] used to call :[] method or for Array
print[].class => NoMethodError: undefined method `[]' for nil:NilClass
print([].class) => Array <returns nil>
Asterisk * used for multiplication or splatting
1 * 5 => 5
[*1..5] => [1, 2, 3, 4, 5]
Ampersand & used for symbol -> proc or logical and
0 & 1 => 0
[1, 2, 3].map(&:to_s) => ["1", "2", "3"]
Or in your case, braces used for block closures or for a hash
... hope it makes sense now ...
I'm trying to define a block that I'll use to pass the the each method of multiple ranges. Rather than redefining the block on each range, I'd like to create a lamba, and pass the lambda as such:
count = 0
procedure = lambda {|v| map[count+=1]=v}
("A".."K").each procedure
("M".."N").each procedure
("P".."Z").each procedure
However, I get the following error:
ArgumentError: wrong number of arguments(1 for 0)
from code.rb:23:in `each'
Any ideas what's going on here?
Tack an ampersand (&) onto the argument, for example:
("A".."K").each &procedure
This signifies that you're passing it as the special block parameter of the method. Otherwise it's interpreted as a normal argument.
It also mirrors they way you'd capture and access the block parameter inside the method itself:
# the & here signifies that the special block parameter should be captured
# into the variable `procedure`
def some_func(foo, bar, &procedure)
procedure.call(foo, bar)
end
some_func(2, 3) {|a, b| a * b }
=> 6
The trick is in using an & which tells Ruby to convert this argument to a Proc if necessary and then use the object as the method’s block. Starting from Ruby 1.9 there's a shortcut for lambda (anonymous) functions. So, you can write code like this:
(1..5).map &->(x){ x*x }
# => [1, 4, 9, 16, 25]
will take each element of the array and compute its power
it is the same as this code:
func = ->(x) { x*x }
(1..5).map &func
for Ruby 1.8:
(1..5).map &lambda {|x| x*x}
# => [1, 4, 9, 16, 25]
To solve your problem you can use Array's method reduce (0 is initial value):
('A'..'K').reduce(0) { |sum,elem| sum + elem.size }
# => 11
Passing a lambda function to reduce is a bit tricky, but the anonymous block is pretty much the same as lambda.
('A'..'K').reduce(0) { |sum, elem| ->(sum){ sum + 1}.call(sum) }
# => 11
Or you could concat letters just like this:
('A'..'K').reduce(:+)
=> "ABCDEFGHIJK"
Convert to lowercase:
('A'..'K').map &->(a){ a.downcase }
=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
In the context of a method definition, putting an ampersand in front of the last parameter indicates that a method may take a block and gives us a name to refer to this block within the method body.
The other answers left something un-clarified that I'd like to expand on. How do we pass an arg and a block to a method?
Suppose we have a method that takes an arg and a block:
def method_with_arg_and_block(arg)
puts arg
yield
end
and a proc:
pr = proc { puts 'This is a proc'}
The answer: It's important that you pass the proc in as an arg with an ampersand rather than appending the proc to the method (like you would do with a block).
For example if you do:
method_with_arg_and_block('my arg') &pr
you will get a "no block given (yield)" exception.
The correct way to call this is:
method_with_arg_and_block('my arg', &pr)
Ruby will take care of converting the proc to a block and appending it to your method. Note: since lambdas are also procs, this will work with lambdas as well.
Thanks to https://medium.com/#sihui/proc-code-block-conversion-and-ampersand-in-ruby-35cf524eef55 for helping me understand this.
I need to convert a passed in argument (single object or collection) to an Array. I don't know what the argument is. If it is an Array already, I want to leave it, otherwise create a one-element array from it. I'm looking to allow both method(:objs => obj) and method(:objs => [obj1, obj2])
This seems to be the best way (Array#to_a returns self):
arg = arg.to_a
But the ruby docs say Object#to_a will soon be obsolete. Is there convenient replacement?
Anything more succinct than this?
arg = arg.respond_to?(:to_a) ? arg.to_a : [arg]
Use the method Kernel#Array:
Array([1,2,3]) #=> [1, 2, 3]
Array(123) #=> [123]
Yes it may look like a class at first but this is actually a method that starts with a capital letter.
Wow, someone just necromanced a really old thread. :-O But since I don't see it included yet, I'll add one more way for completeness' sake:
arg = [*arg]
This will splat the argument if it already is an array (thus removing one level of nesting) or create a one-argument array otherwise:
arg = [1,2,3]
[*arg] #=> [1, 2, 3]
arg = 1
[*arg] #=> [1]
It seems only Object.to_a is deprecated, removing a default to_a and forcing each class to define its own (e.g., Hash.to_a).
self.to_a #=> -:1: warning: default `to_a' will be obsolete
"hello".to_a #=> ["hello"]
Time.new.to_a #=> [39, 54, 8, 9, 4, 2003, 3, 99, true, "CDT"]
h = { "c" => 300, "a" => 100, "d" => 400, "c" => 300 }
h.to_a #=> [["a", 100], ["c", 300], ["d", 400]]
If your argument is an instance of Object, try:
Hash.new(obj).to_a
#Daniel [comment to Ollivier]: The point is that I don't know what the argument is. If it is an array already, I want to leave it, otherwise create a one-element array.
If that's the case, try:
obj = [obj] if !obj.is_a?(Array)
You can take the duck typing aproach if that suits the problem better, make a list of all the methods you need, and check if the object already have them, if not, make it an array:
[:[], :each, :etc...].all? { |m| obj.respond_to? m } ? obj : [obj]
The advantage is that you give the object a chance to implement it's own semantics for indexed access.
I do this a lot, and always use:
arg = [arg] unless arg.is_a?(Array)
Though if you know you're never passing in arrays as individual arguments you can also do:
arg = [arg].flatten
I'm not sure if this helps, but what I often need is not that the arg be an array, but that the arg responds to each.
arg = [arg] unless arg.respond_to? :each
What about Array.new(1, arg)?