What does the map method do in Ruby?
The map
method takes an enumerable object and a block, and runs the block for each element, outputting each returned value from the block (the original object is unchanged unless you use map!)
:
[1, 2, 3].map { |n| n * n } #=> [1, 4, 9]
Array
and Range
are enumerable types. map
with a block returns an Array. map!
mutates the original array.
Where is this helpful, and what is the difference between map!
and each
? Here is an example:
names = ['danil', 'edmund']
# here we map one array to another, convert each element by some rule
names.map! {|name| name.capitalize } # now names contains ['Danil', 'Edmund']
names.each { |name| puts name + ' is a programmer' } # here we just do something with each element
The output:
Danil is a programmer
Edmund is a programmer
What does map(&:name) mean in Ruby?
It's shorthand for tags.map(&:name.to_proc).join(' ')
If foo
is an object with a to_proc
method, then you can pass it to a method as &foo
, which will call foo.to_proc
and use that as the method's block.
The Symbol#to_proc
method was originally added by ActiveSupport but has been integrated into Ruby 1.8.7. This is its implementation:
class Symbol
def to_proc
Proc.new do |obj, *args|
obj.send self, *args
end
end
end
How to understand Ruby's .each and .map
The map
method takes an enum
given some block, and iterates through it doing some logic. In your case the logic is x+1
. As you say it will not mutate anything unless you use !
.
each
is simply returning the array that is being called.
Let's take an example of:
names = ["bob"]
If we do:
names.each{|names| names + "somestring"}
the output is still ["bob"]
. The reason your second example is different is due to the puts
.
As an exercise try doing:
y = [1,2,3].each {|x| puts x + 1}
You will get:
2
3
4
[1,2,3]
In Ruby, what is .map method with rand?
code = (0...16).map { rand(10).to_s }.join
Is used to generate the random string which contains (0 to 9) of length 16. .map
will return an array with length of number of times it is iterating (here 16 times). .join
is used to join all this 16
elements & return a string
2.2.4 :004 > code = (0...16).map {rand(10).to_s}
=> ["9", "2", "7", "4", "8", "2", "2", "9", "0", "8", "5", "1", "3", "2", "7", "8"]
2.2.4 :005 > code = (0...16).map {rand(10).to_s}.join
=> "8371524929956722"
2.2.4 :006 > code = (0...16).map {rand(10).to_s}.join
=> "4111661481960314"
2.2.4 :007 >
you can use following as well to generate the same result
code = rand(10 ** 16).to_s
=> "7066995392533658"
2.2.4 :011 > code = rand(10 ** 16).to_s
=> "9149902415985481"
Ruby Map Method edits the original array?
Think of using:
map
as saying "I want to create new data based on existing data"each
as saying "I either want to not change any data, or change existing data"
Having this in mind, what you are doing is using map
with array to create new array based on existing one, and then using each
to modify characters in existing strings. This is why the strings in the original array end up modified.
To fix this use map
twice, first to "create new array based on existing array", and then the second time to "create new string based on existing string". This way the original strings won't get modified.
def removal(arr)
letters ="i"
p arr
new_array = arr.map do |word|
word.chars.map do |char|
letters.include?(char) ? '*' : char
end.join
end
p arr
p new_array
end
removal(["hiiiiiigh","git", "training"]) #=> ["hiiiiiigh", "git", "training"]
# ["hiiiiiigh", "git", "training"]
# ["h******gh", "g*t", "tra*n*ng"]
More practical solution to this problem would be something like this:
def censor(strings, forbidden_chars_string, censor_char = '*')
re = Regexp.union(forbidden_chars_string.chars)
strings.map {|str| str.gsub(re, censor_char) }
end
p ["hiiiiiigh","git", "training"] #=> ["hiiiiiigh", "git", "training"]
p censor(["hiiiiiigh","git", "training"], "i") #=> ["h******gh", "g*t", "tra*n*ng"]
p censor(["hiiiiiigh","git", "training"], "gn", '_') #=> ["hiiiiii_h", "_it", "trai_i__"]
What does map(&:name) do in this Ruby code?
events.map(&:name)
is exactly equivalent to
events.map{|x| x.name}
it is just convenient syntactic sugar.
For more details, check out the Symbol#to_proc
method here. Here, :name
is being coerced to a proc.
By the way, this comes up often here - it's just very hard to google or otherwise search for 'the colon thing with an ampersand' :).
What is the use of map method in ruby?
In your example, when you want to print each value individually right away, each
is better. map
is useful when you want to save the new versions your elements back into an array, and use that data later in your program.
For instance, say you wanted to forget whether the names had ever been lower or uppercase. Everywhere in your program, the names will be uppercase, so you just want to convert them to uppercase now and be done with that.
a = ["kevin","john","ryan"]
a = a.map{ |n| n.upcase }
Compare that to using each
– you would have to use each_with_index
, actually, since you need a way to assign the new values back:
a = ["kevin","john","ryan"]
a.each_with_index do |n, i|
a[i] = n.upcase
end
This is the kind of situation map
is for. Getting a new Enumerable
with changed values, so that you can use the new values later.
By the way, as a shortcut, if you’re assigning a map
ped variable back to itself, instead of a = a.map{}
, you can use a.map!{}
.
Another situation is if you wanted to print all names with an even number of letters. If you used each
, here’s how it would look:
a = ["kevin","john","ryan"]
a.each do |n|
if n.size.even?
puts n.upcase
end
end
If you used map
, that would give you an array back. Then you could pass that array to select
, and finally use each
to print the values. This separates the steps more clearly for anyone reading the code, and makes your code more modular if you want to extend it later.
a = ["kevin","john","ryan"]
a.map(&:upcase) \
.select{ |n| n.size.even? } \
.each{ |n| puts n }
The last line could also be this:
.each(&Kernel.method(:puts))
but that is probably unnecessarily confusing for such a small bit of code. What that does is convert the global puts
method into a block using the &
operator. Kernel
holds all global methods, and .method
is the way you get a variable with a method from a class. So .each(&Kernel.method(:puts))
says “get the global puts
method, and turn it into a block so that puts
is called with the block arguments as parameters”. But in this case, it’s clearer and simpler to write .each{ |n| puts n }
.
What is map(&:id) in Rails?
1 )
You should read some tutorials on map
to get acquainted.
https://www.rubyguides.com/2018/10/ruby-map-method
But the short answer is that running user.cnae_classifications.map(&:id)
will loop over all cnae_classifications
and extract the id
from them and put them all into an array. The &
character allows for map
shorthand to avoid passing an entire block.
From the link above:
2 )
The #create
method can accept a key-value hash of known attributes (known to the class in question, in this case that is UserCnaeClassification
) to assign upon creation. So you're basically right, they are key-value pairs but they are specific to this class/object. Those same keys might not work on another class/object.
Additional reading: https://guides.rubyonrails.org/active_record_basics.html#create
Related Topics
Disable Activerecord For Rails 4
In Ruby on Rails, to Extend the String Class, Where Should the Code Be Put In
How to Get Argument Names Using Reflection
Using Sinatra For Larger Projects Via Multiple Files
What Does a Double * (Splat) Operator Do
Rails Has_Many :Through Find by Extra Attributes in Join Model
How to Find an Item in Array Which Has the Most Occurrences
How to Have Methods Inside Methods
Ruby: Kind_Of? Vs. Instance_Of? Vs. Is_A
Why Does Installing Nokogiri on MAC Os Fail With Libiconv Is Missing
Continuously Read from Stdout of External Process in Ruby
How to Create an Average from a Ruby Array
Rails: Access to Current_User from Within a Model in Ruby on Rails
What Does ||= (Or-Equals) Mean in Ruby
The Authorization Mechanism You Have Provided Is Not Supported. Please Use Aws4-Hmac-Sha256