Додайте пару ключ / значення до хешу за допомогою << у Ruby


80

У Ruby можна додавати значення до існуючих масивів, використовуючи <<:

a = []
a << "foo"

але, чи можете ви також додати пари ключ / значення до існуючого хешу?

h = {}
h << :key "bar"

Я знаю, що ти можеш:

h[:key] = ""
h[:key] << "bar"

але це не я хочу.

Дякую.


20
Чому ні h[:key] = "bar"?
Хаулет

4
Це не працює:h[:key] << "bar"
Кріс Нільсен,

Відповіді:


141

Існує merge!.

h = {}
h.merge!(key: "bar")
# => {:key=>"bar"}

3
Я не думаю, що це merge!кваліфікується як просто створення нової пари ключ / значення, оскільки насправді використовується для іншої мети.
PericlesTheo

Влучне зауваження. Я думаю, що це також може закінчитися залежно від інших факторів, які ОП не розміщував.
Michael Durrant

1
Ах, спасибі. Схоже, метод store робить щось подібне. Це було здебільшого академічне питання, оскільки я бачив << як спосіб додавання до масивів, але хотів перевірити, чи працює це для хешів. Знову дякую.
jcarpio

5
Різниця в наступному: storeпросто додає нову пару, все одно, чи ключ уже існує. з merge!тим НЕ менш, записи з повторюваними ключами перевизначені тому метод робить трохи більше , ніж просто додавання пари. Якщо порівняти ці два, ви виявите storeшвидшими (тривіальними, однак особливо на невеликих хешах)
PericlesTheo

2
@jcarpio Дякую. Hash#merge!повертає хеш приймача так само, як Array#<<повертає масив приймача. Hash#storeце зовсім інша річ. Крім того, маючи на увазі хеш-синтаксис цукру key: "bar"в позиції аргументу, я вважав, що це найближче до вашого позначення. Я знав, що це ближче до того, що ти хотів.
sawa

89

Оскільки хеші за своєю суттю не впорядковані, немає поняття додавання. Однак хеші Ruby з 1.9 підтримують порядок вставки. Ось способи додавання нових пар ключ / значення.

Найпростішим рішенням є

h[:key] = "bar"

Якщо ви хочете метод, використовуйте store:

h.store(:key, "bar")

Якщо ви дійсно, дуже хочете використовувати оператор "лопата" ( <<), він фактично додається до значення хешу як масиву, і ви повинні вказати ключ:

h[:key] << "bar"

Вищевказане працює лише тоді, коли ключ існує. Щоб додати новий ключ, вам потрібно ініціалізувати хеш значенням за замовчуванням, що можна зробити так:

h = Hash.new {|h, k| h[k] = ''}
h[:key] << "bar"

У вас може виникнути спокуса виправити мавпу Hash, щоб включити оператор лопати, який працює так, як ви написали:

class Hash
  def <<(k,v)
    self.store(k,v)
  end
end

Однак це не успадковує "синтаксичний цукор", що застосовується до оператора лопати в інших контекстах:

h << :key, "bar" #doesn't work
h.<< :key, "bar" #works

Ретельно! Дякуємо за внесок та розуміння.
jcarpio

Зауважимо, що станом на Ruby 1.9, хеші впорядковані.
сталь

1
Ruby 1.9+ підтримує порядок вставки, але хеш як структура даних не має концепції будь-якого властивого порядку.
Марк Томас

27

Ні, я не думаю, що ви можете додавати пари ключ / значення. Єдине, що мені найближче відомо, це використання storeметоду:

h = {}
h.store("key", "value")

3

Можливо, ви хочете злиття Hash #?

1.9.3p194 :015 > h={}
 => {} 
1.9.3p194 :016 > h.merge(:key => 'bar')
 => {:key=>"bar"} 
1.9.3p194 :017 > 

Якщо ви хочете змінити масив на місці, використовуйте merge!

1.9.3p194 :016 > h.merge!(:key => 'bar')
 => {:key=>"bar"} 

Я не думаю, mergeщо це хороша ідея, оскільки вона повертає новий масив; не додавання нової пари до існуючого хешу.
PericlesTheo

Як щодо merge!(тобто існуючого масиву) замість merge?
Michael Durrant

1
merge!технічно працює в цьому контексті, але я думаю, що його слід використовувати для об'єднання двох хешів, а не просто для додавання нової пари. Крім того, якщо ви тестуєте merge!, це повільніше, ніж store;)
PericlesTheo

3

Подібні, як вони є, merge!і по- різному storeобробляти існуючі хеші залежно від назв клавіш, і тому впливатимуть на ваші уподобання. Крім цього з точки зору синтаксису, merge!«s key: "value"синтаксис тісно збігається з JavaScript і Python. Я завжди ненавидів пари, які розділяють комами ключ-значення, особисто.

hash = {}
hash.merge!(key: "value")
hash.merge!(:key => "value")
puts hash

{:key=>"value"}

hash = {}
hash.store(:key, "value")
hash.store("key", "value")
puts hash

{:key=>"value", "key"=>"value"}

Щоб оператор лопати <<працював, я порадив би використовувати відповідь Марка Томаса .


1

Мені довелося зробити подібне, але мені потрібно було додати значення за допомогою тих самих ключів. Коли я використовую злиття або оновлення, я не можу натискати значення тими самими клавішами. Тому мені довелося використовувати масив хешів.

    my_hash_static = {:header =>{:company => 'xx', :usercode => 'xx', :password => 'xx',
                      :type=> 'n:n', :msgheader => from}, :body=>[]}
    my_hash_dynamic = {:mp=>{:msg=>message, :no=>phones} }        
    my_hash_full = my_hash_static[:body].push my_hash_dynamic
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.