Як замінити хеш-ключ на інший


192

У мене є умова, де я отримую хеш

  hash = {"_id"=>"4de7140772f8be03da000018", .....}

і я хочу цей хеш як

  hash = {"id"=>"4de7140772f8be03da000018", ......}

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


Це може допомогти вам: stackoverflow.com/questions/4044451/…
роз'їдає

+1 за корисне запитання
ashisrai_

@ a5his: Я радий, що це допомогло :)
Manish Das

Відповіді:


711
hash[:new_key] = hash.delete :old_key

8
Врятували мені пару LOC, люблю це!
nicohvi

10
Мені часто не подобається "розумний" рубіновий код, тому що потрібно трохи часу, щоб розповісти, що він насправді робить. З іншого боку, ваше рішення є простим та описовим.
Лукас

3
Це справді має бути прийнятою відповіддю! Легко, чисто і прямо до речі!
GigaBass

1
Ця відповідь елегантна, але насправді не відповідає на питання. У публікації зазначено, що ключі, які потребують заміни, невідомі ... Ми знаємо лише, що вони починаються з підкреслення, ми не знаємо, що саме є ключами.
Дзель

2
таким чином, це створює нову пару ключ / значення, де ви вказуєте новий ключ і отримуєте значення з того, що hash.delete :old_keyповертається, а для видалення використовує старий ключ. WOW, я хочу, щоб його десь татуювали :-D Спасибі
Bart C

136

рейки Hash має для нього стандартний метод:

hash.transform_keys{ |key| key.to_s.upcase }

http://api.rubyonrails.org/classes/Hash.html#method-i-transform_keys

UPD: метод рубіну 2,5


4
Це метод Rails, не стандартний. Хоча хороша відповідь.
користувач2422869

1
Також цей метод не може працювати з хеш-ключами рекурсивно.
Серхіо Белевський

5
deep_transform_keys можна використовувати для цього :) apidock.com/rails/v4.2.1/Hash/deep_transform_keys
gayavat

1
Нарешті! Це саме те, що я шукав!
TiSer

4
Це стандартна частина мови станом на Ruby 2.5: docs.ruby-lang.org/en/trunk/Hash.html#method-i-transform_keys
Девід Грейсон,

39

Якщо всі клавіші - це рядки, і всі вони мають префікс підкреслення, тоді ви можете закріпити хеш на цьому:

h.keys.each { |k| h[k[1, k.length - 1]] = h[k]; h.delete(k) }

k[1, k.length - 1]Трохи захоплює все , kкрім першого символу. Якщо ви хочете копію, то:

new_h = Hash[h.map { |k, v| [k[1, k.length - 1], v] }]

Або

new_h = h.inject({ }) { |x, (k,v)| x[k[1, k.length - 1]] = v; x }

Ви також можете використовувати, subякщо ви не любите k[]позначення для вилучення підрядка:

h.keys.each { |k| h[k.sub(/\A_/, '')] = h[k]; h.delete(k) }
Hash[h.map { |k, v| [k.sub(/\A_/, ''), v] }]
h.inject({ }) { |x, (k,v)| x[k.sub(/\A_/, '')] = v; x }

І, якщо лише деякі клавіші мають префікс підкреслення:

h.keys.each do |k|
  if(k[0,1] == '_')
    h[k[1, k.length - 1]] = h[k]
    h.delete(k)
  end
end

Аналогічні зміни можна зробити для всіх інших варіантів вище, окрім цих двох:

Hash[h.map { |k, v| [k.sub(/\A_/, ''), v] }]
h.inject({ }) { |x, (k,v)| x[k.sub(/\A_/, '')] = v; x }

має бути гаразд з ключами, у яких немає додаткових підстав підкреслення без додаткових модифікацій.


Ваша відповідь спрацювала, але після підопічного я знайшов кілька таких хешів
Manish Das

3
{"_id" => "4de7140772f8be03da000018", "_type" => "WorkStation", "created_at" => "2011-06-02T10: 24: 35 + 05: 45", "input_header_ids" => [], "line_id "=>" 4de7140472f8be03da000017 "," updated_at "=>" 2011-06-02T10: 24: 35 + 05: 45 "}
Manish Das

2
{"id" => "4de7140772f8be03da000018", "type" => "WorkStation", "reated_at" => "2011-06-02T10: 24: 35 + 05: 45", "nput_header_ids" => [], "ine_id "=>" 4de7140472f8be03da000017 "," pded_at "=>" 2011-06-02T10: 24: 35 + 05: 45 "}
Manish Das

@Manish: Я сказав: "Якщо всі клавіші - це рядки, і всі вони мають префікс підкреслення". Я включив приклад підходу для ваших "клавіш без підкреслення префіксів" в оновлення.
mu занадто короткий

2
@Manish: "k" - це "ключ", "v" - це "значення", "x" - це "я не знаю, як його називати, але я був підготовлений як математик, тому я називаю це x".
mu занадто короткий

14

Ви можете зробити

hash.inject({}){|option, (k,v) | option["id"] = v if k == "_id"; option}

Це має працювати для вашого випадку!


11

Якщо ми хочемо перейменувати певний ключ у хеші, ми можемо це зробити так:
Припустимо, мій хеш my_hash = {'test' => 'ruby hash demo'}
зараз Я хочу замінити 'тест' на 'повідомлення', тоді:
my_hash['message'] = my_hash.delete('test')


Як ваша відповідь тоді є вирішенням моєї проблеми? Якщо ви вважаєте, що це корисно, то ви могли б додати коментар до цього питання. Моє запитання полягало не в тому, щоб замінити ключ іншим ключем, рішення, яке ви дали, є дуже базовим властивістю Hash. в моєму випадку це не так: hash[:new_key] = has[:old_key]натомість це:, hash[:dynamic_key] = hash[:_dynamic_key]було чітке питання про регулярний вираз, а не проста хеш-заміна.
Manish Das

2
Я прийшов до цього за допомогою пошуку в Google і хотів відповіді @ Swapnil. Спасибі
toobulkeh

10
h.inject({}) { |m, (k,v)| m[k.sub(/^_/,'')] = v; m }

4
Мені подобається, що ви намагалися використовувати регулярний вираз, щоб правильно відфільтрувати підкреслення, але ви повинні знати, що в рубіні, на відміну від javascript та інших, / ^ / означає "початок рядка АБО ЛІНІЯ", і / $ / означає 'кінець рядок АБО LINE '. У цьому випадку малоймовірно, що в ключах є нові рядки, але слід пам’ятати, що використання цих двох операторів у рубіні - це не лише схильність до помилок, але й дуже небезпечно при неправильному використанні під час перевірки проти ін'єкцій. Дивіться тут для пояснення. Сподіваємось, ви не проти поширити інформацію.
Jorn van de Beek


1

Я переборщив і придумав наступне. Моя мотивація цього полягала в тому, щоб приєднати хеш-ключі, щоб уникнути конфліктів між областями при об'єднанні хешей.

Приклади

Розширити клас хешу

Додає метод rekey в екземпляри Hash.

# Adds additional methods to Hash
class ::Hash
  # Changes the keys on a hash
  # Takes a block that passes the current key
  # Whatever the block returns becomes the new key
  # If a hash is returned for the key it will merge the current hash 
  # with the returned hash from the block. This allows for nested rekeying.
  def rekey
    self.each_with_object({}) do |(key, value), previous|
      new_key = yield(key, value)
      if new_key.is_a?(Hash)
        previous.merge!(new_key)
      else
        previous[new_key] = value
      end
    end
  end
end

Приклад прикладу

my_feelings_about_icecreams = {
  vanilla: 'Delicious',
  chocolate: 'Too Chocolatey',
  strawberry: 'It Is Alright...'
}

my_feelings_about_icecreams.rekey { |key| "#{key}_icecream".to_sym }
# => {:vanilla_icecream=>"Delicious", :chocolate_icecream=>"Too Chocolatey", :strawberry_icecream=>"It Is Alright..."}

Приклад обрізки

{ _id: 1, ___something_: 'what?!' }.rekey do |key|
  trimmed = key.to_s.tr('_', '')
  trimmed.to_sym
end
# => {:id=>1, :something=>"what?!"}

Вирівнювання та додавання "Області"

Якщо ви повернете хеш назад для повторної переробки, він об'єднає хеш, що дозволяє вирівняти колекції. Це дозволяє нам додавати область нашим ключам при вирівнюванні хеша, щоб уникнути перезапису ключа при злитті.

people = {
  bob: {
    name: 'Bob',
    toys: [
      { what: 'car', color: 'red' },
      { what: 'ball', color: 'blue' }
    ]
  },
  tom: {
    name: 'Tom',
    toys: [
      { what: 'house', color: 'blue; da ba dee da ba die' },
      { what: 'nerf gun', color: 'metallic' }
    ]
  }
}

people.rekey do |person, person_info|
  person_info.rekey do |key|
    "#{person}_#{key}".to_sym
  end
end

# =>
# {
#   :bob_name=>"Bob",
#   :bob_toys=>[
#     {:what=>"car", :color=>"red"},
#     {:what=>"ball", :color=>"blue"}
#   ],
#   :tom_name=>"Tom",
#   :tom_toys=>[
#     {:what=>"house", :color=>"blue; da ba dee da ba die"},
#     {:what=>"nerf gun", :color=>"metallic"}
#   ]
# }

0

Попередні відповіді досить хороші, але вони можуть оновити оригінальні дані. Якщо ви не хочете, щоб це впливало на оригінальні дані, ви можете спробувати мій код.

 newhash=hash.reject{|k| k=='_id'}.merge({id:hash['_id']})

Спочатку він ігнорує ключ '_id', а потім об'єднається з оновленим.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.