Ответы:
map
Метод принимает перечислимый объект и блок, и запускает блок для каждого элемента, каждый вывод возвращаемого значения из блока (исходный объект не изменяется , если не используется map!)
:
[1, 2, 3].map { |n| n * n } #=> [1, 4, 9]
Array
и Range
перечислимые типы. map
с блоком возвращает массив. map!
мутирует исходный массив.
Где это полезно, и в чем разница между map!
и each
? Вот пример:
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
Выход:
Danil is a programmer
Edmund is a programmer
map
как если бы это былоmap!
map
вместе с select
и each
является одной из рабочих лошадок Руби в моем коде.
Это позволяет вам выполнить операцию над каждым из объектов вашего массива и вернуть их все в одном месте. Примером может быть увеличение массива чисел на единицу:
[1,2,3].map {|x| x + 1 }
#=> [2,3,4]
Если вы можете запустить один метод для элементов вашего массива, вы можете сделать это в стиле сокращения следующим образом:
Чтобы сделать это с приведенным выше примером, вы должны сделать что-то вроде этого
class Numeric
def plusone
self + 1
end
end
[1,2,3].map(&:plusone)
#=> [2,3,4]
Чтобы проще использовать технику быстрого доступа, давайте рассмотрим другой пример:
["vanessa", "david", "thomas"].map(&:upcase)
#=> ["VANESSA", "DAVID", "THOMAS"]
Преобразование данных в Ruby часто включает каскад map
операций. Изучите map
& select
, они являются одними из самых полезных методов Ruby в основной библиотеке. Они так же важны, как и each
.
( map
также является псевдонимом для collect
. Используйте то, что лучше всего подходит для вас концептуально.)
Более полезная информация:
Если объект Enumerable, на котором вы работаете each
или map
на котором находится, содержит набор элементов Enumerable (хэши, массивы), вы можете объявить каждый из этих элементов внутри ваших блочных каналов следующим образом:
[["audi", "black", 2008], ["bmw", "red", 2014]].each do |make, color, year|
puts "make: #{make}, color: #{color}, year: #{year}"
end
# Output:
# make: audi, color: black, year: 2008
# make: bmw, color: red, year: 2014
В случае Hash (также Enumerable
объекта, Hash - это просто массив кортежей со специальными инструкциями для интерпретатора). Первый «параметр трубы» - это ключ, второй - значение.
{:make => "audi", :color => "black", :year => 2008}.each do |k,v|
puts "#{k} is #{v}"
end
#make is audi
#color is black
#year is 2008
Чтобы ответить на актуальный вопрос:
Предполагая, что params
это хеш, это будет лучший способ отобразить его: используйте два параметра блока вместо одного, чтобы захватить пару ключ-значение для каждого интерпретируемого кортежа в хэше.
params = {"one" => 1, "two" => 2, "three" => 3}
params.each do |k,v|
puts "#{k}=#{v}"
end
# one=1
# two=2
# three=3
NoMethodError: private method 'plusone' called for 1:Fixnum
в ruby 2 и «неправильное количество аргументов» в ruby 1.9 / 1.8. Во всяком случае, я использовал лямбда: plusone = ->(x) { x + 1 }
затем вынуть символ спецификатора: [1,2,3].map(&plusone)
.
private
внутри класса, где вы помещаете свой метод перед тем, как поместить свой метод
0..param_count
означает "до и включая param_count".
0...param_count
означает "до, но не включая param_count".
Range#map
не возвращает Enumerable
, фактически отображает его в массив. Это так же, как Range#to_a
.
Он «сопоставляет» функцию с каждым элементом в Enumerable
- в данном случае, диапазоне. Таким образом, он будет вызывать блок, переданный один раз для каждого целого числа от 0 доparam_count
(исключая - вы правы насчет точек), и возвращать массив, содержащий каждое возвращаемое значение.
Вот документация для Enumerable#map
. У него также есть псевдоним collect
.
Range#map
самом деле преобразует его в массив.
Enumerable
, как каждая. Я думал, что это сделал.
Карта является частью перечислимого модуля. Очень похоже на «собирать» Например:
Class Car
attr_accessor :name, :model, :year
Def initialize (make, model, year)
@make, @model, @year = make, model, year
end
end
list = []
list << Car.new("Honda", "Accord", 2016)
list << Car.new("Toyota", "Camry", 2015)
list << Car.new("Nissan", "Altima", 2014)
p list.map {|p| p.model}
Карта предоставляет значения, повторяющиеся в массиве, которые возвращаются параметрами блока.
#each
#each
запускает функцию для каждого элемента в массиве. Следующие два фрагмента кода эквивалентны:
x = 10
["zero", "one", "two"].each{|element|
x++
puts element
}
x = 10
array = ["zero", "one", "two"]
for i in 0..2
x++
puts array[i]
end
#map
#map
применяет функцию к каждому элементу массива, возвращая полученный массив. Следующее эквивалентно:
array = ["zero", "one", "two"]
newArray = array.map{|element| element.capitalize()}
array = ["zero", "one", "two"]
newArray = []
array.each{|element|
newArray << element.capitalize()
}
#map!
#map!
это как #map
, но изменяет массив на месте. Следующее эквивалентно:
array = ["zero", "one", "two"]
array.map!{|element| element.capitalize()}
array = ["zero", "one", "two"]
array = array.map{|element| element.capitalize()}
map
является общим «функциональным» методом, который можно найти в перечисляемых объектах, используемых для преобразования значений в последовательности (с особыми соображениями)...
и...
способы создания диапазонов. Кроме того, ознакомьтесь с REPL, где вы можете попробовать этот материал самостоятельно! :)