Изменение каждого значения в хэше в Ruby - PullRequest
151 голосов
/ 04 марта 2011

Я хочу изменить каждое значение в хэше, чтобы добавить «%» до и после значения, поэтому

{ :a=>'a' , :b=>'b' }

необходимо изменить на

{ :a=>'%a%' , :b=>'%b%' }

Что лучшеспособ сделать это?

Ответы [ 10 ]

245 голосов
/ 04 сентября 2014

В Ruby 2.1 и выше вы можете сделать

{ a: 'a', b: 'b' }.map { |k, str| [k, "%#{str}%"] }.to_h
165 голосов
/ 04 марта 2011

Если вы хотите, чтобы сами фактические строки мутировали на месте (возможно и желательно влияя на другие ссылки на те же строковые объекты):

# Two ways to achieve the same result (any Ruby version)
my_hash.each{ |_,str| str.gsub! /^|$/, '%' }
my_hash.each{ |_,str| str.replace "%#{str}%" }

Если вы хотите, чтобы хэш изменился на месте, но не хотите влиять на строки (вы хотите, чтобы он получал новые строки):

# Two ways to achieve the same result (any Ruby version)
my_hash.each{ |key,str| my_hash[key] = "%#{str}%" }
my_hash.inject(my_hash){ |h,(k,str)| h[k]="%#{str}%"; h }

Если вы хотите новый хеш:

# Ruby 1.8.6+
new_hash = Hash[*my_hash.map{|k,str| [k,"%#{str}%"] }.flatten]

# Ruby 1.8.7+
new_hash = Hash[my_hash.map{|k,str| [k,"%#{str}%"] } ]
90 голосов
/ 06 января 2017

В Ruby 2.4 введен метод Hash#transform_values!, который вы можете использовать.

{ :a=>'a' , :b=>'b' }.transform_values! { |v| "%#{v}%" }
# => {:a=>"%a%", :b=>"%b%"} 
80 голосов
/ 13 сентября 2014

Лучший способ изменить значения хэша:

hash.update(hash){ |_,v| "%#{v}%" }

Меньше кода и четких намерений. Также быстрее, потому что новые объекты не выделяются за пределы значений, которые должны быть изменены.

28 голосов
/ 01 декабря 2012

Немного более читаемый, map это массив одноэлементных хешей и reduce, что с merge

the_hash.map{ |key,value| {key => "%#{value}%"} }.reduce(:merge)
17 голосов
/ 08 апреля 2016

Для этой задачи существует новый метод Rails way :) http://api.rubyonrails.org/classes/Hash.html#method-i-transform_values

16 голосов
/ 04 марта 2011

Один метод, который не привносит побочных эффектов в оригинал:

h = {:a => 'a', :b => 'b'}
h2 = Hash[h.map {|k,v| [k, '%' + v + '%']}]

Hash # map также может быть интересным, поскольку объясняет, почему Hash.map не делаетне возвращает хэш (именно поэтому результирующий массив пар [key,value] преобразуется в новый хэш) и предоставляет альтернативные подходы к тому же общему шаблону.

Счастливое кодирование.

[Отказ от ответственности: я не уверен, что семантика Hash.map изменилась в Ruby 2.x]

15 голосов
/ 04 марта 2011
my_hash.each do |key, value|
  my_hash[key] = "%#{value}%"
end
7 голосов
/ 20 мая 2014

Hash.merge!самое чистое решение

o = { a: 'a', b: 'b' }
o.merge!(o) { |key, value| "%#{ value }%" }

puts o.inspect
> { :a => "%a%", :b => "%b%" }
5 голосов
/ 25 ноября 2016

После тестирования с RSpec следующим образом:

describe Hash do
  describe :map_values do
    it 'should map the values' do
      expect({:a => 2, :b => 3}.map_values { |x| x ** 2 }).to eq({:a => 4, :b => 9})
    end
  end
end

Вы можете реализовать Hash # map_values ​​следующим образом:

class Hash
  def map_values
    Hash[map { |k, v| [k, yield(v)] }]
  end
end

Функцию затем можно использовать так:

{:a=>'a' , :b=>'b'}.map_values { |v| "%#{v}%" }
# {:a=>"%a%", :b=>"%b%"}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...