Лучший способ конвертировать строки в символы в хэше - PullRequest
231 голосов
/ 29 апреля 2009

Какой (самый быстрый / чистый / простой) способ преобразовать все ключи в хэше из строк в символы в Ruby?

Это было бы удобно при разборе YAML.

my_hash = YAML.load_file('yml')

Я бы хотел использовать:

my_hash[:key] 

Вместо:

my_hash['key']

Ответы [ 31 ]

2 голосов
/ 24 октября 2015

Это для людей, которые используют mruby и не имеют никакого определенного метода symbolize_keys:

class Hash
  def symbolize_keys!
    self.keys.each do |k|
      if self[k].is_a? Hash
        self[k].symbolize_keys!
      end
      if k.is_a? String
        raise RuntimeError, "Symbolizing key '#{k}' means overwrite some data (key :#{k} exists)" if self[k.to_sym]
        self[k.to_sym] = self[k]
        self.delete(k)
      end
    end
    return self
  end
end

Метод:

  • символизирует только те клавиши, которые String
  • если символизировать строку означает потерять некоторую информацию (перезаписать часть хеша), поднимите RuntimeError
  • символизирует также рекурсивно содержащиеся хэши
  • вернуть символьный хэш
  • работает на месте!
1 голос
/ 27 ноября 2015

Если вы хотите ванильное рубиновое решение и, как я, у вас нет доступа к ActiveSupport, здесь есть глубокое символическое решение (очень похожее на предыдущие)

    def deep_convert(element)
      return element.collect { |e| deep_convert(e) } if element.is_a?(Array)
      return element.inject({}) { |sh,(k,v)| sh[k.to_sym] = deep_convert(v); sh } if element.is_a?(Hash)
      element
    end
1 голос
/ 05 июля 2015

Массив, который мы хотим изменить.

strings = ["HTML", "CSS", "JavaScript", "Python", "Ruby"]

Создайте новую переменную как пустой массив, чтобы мы могли «.push» символы в.

символов = []

Здесь мы определяем метод с блоком.

strings.each {| x | symbols.push (x.intern)}

Конец кода.

Так что это, вероятно, самый простой способ преобразования строк в символы в ваших массивах в Ruby. Создайте массив строк, затем создайте новую переменную и установите переменную в пустой массив. Затем выберите каждый элемент в первом массиве, который вы создали с помощью метода .each. Затем используйте блочный код для «.push» всех элементов вашего нового массива и используйте «.intern или .to_sym» для преобразования всех элементов в символы.

Символы быстрее, потому что они экономят больше памяти в вашем коде, и вы можете использовать их только один раз. Символы чаще всего используются для ключей в хэше, и это здорово. Я не лучший программист на ruby, но эта форма кода мне очень помогла. Если кто-нибудь знает лучший способ, поделитесь им, и вы можете использовать этот метод и для хэша!

1 голос
/ 22 ноября 2018

Начиная с Psych 3.0 вы можете добавить symbolize_names: опция

Psych.load("---\n foo: bar") # => {"foo"=>"bar"}

Psych.load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}

Примечание: если у вас более низкая версия Psych, чем 3.0 symbolize_names: будет игнорироваться.

My Ubuntu 18.04 включает его из коробки с ruby ​​2.5.1p57

0 голосов
/ 17 октября 2018

Аналогично предыдущим решениям, но написано немного по-другому.

  • Это позволяет использовать хэш, который является вложенным и / или имеет массивы.
  • Получить преобразование ключей в строку в качестве бонуса.
  • Код не изменяет переданный хэш.

    module HashUtils
      def symbolize_keys(hash)
        transformer_function = ->(key) { key.to_sym }
        transform_keys(hash, transformer_function)
      end
    
      def stringify_keys(hash)
        transformer_function = ->(key) { key.to_s }
        transform_keys(hash, transformer_function)
      end
    
      def transform_keys(obj, transformer_function)
        case obj
        when Array
          obj.map{|value| transform_keys(value, transformer_function)}
        when Hash
          obj.each_with_object({}) do |(key, value), hash|
            hash[transformer_function.call(key)] = transform_keys(value, transformer_function)
          end
        else
          obj
        end
      end
    end
    
0 голосов
/ 03 июня 2015

Это не совсем одна строка, но она превращает все строковые ключи в символы, в том числе вложенные:

def recursive_symbolize_keys(my_hash)
  case my_hash
  when Hash
    Hash[
      my_hash.map do |key, value|
        [ key.respond_to?(:to_sym) ? key.to_sym : key, recursive_symbolize_keys(value) ]
      end
    ]
  when Enumerable
    my_hash.map { |value| recursive_symbolize_keys(value) }
  else
    my_hash
  end
end
0 голосов
/ 24 июля 2011
ruby-1.9.2-p180 :001 > h = {'aaa' => 1, 'bbb' => 2}
 => {"aaa"=>1, "bbb"=>2} 
ruby-1.9.2-p180 :002 > Hash[h.map{|a| [a.first.to_sym, a.last]}]
 => {:aaa=>1, :bbb=>2}
0 голосов
/ 02 июля 2015

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

my_hash = { "a" => 1, "b" => "string", "c" => true }

my_hash.keys.each { |key| my_hash[key.to_sym] = my_hash.delete(key) }

my_hash
=> {:a=>1, :b=>"string", :c=>true}

Hash # delete возвращает значение удаленного ключа

0 голосов
/ 16 февраля 2016

symbolize_keys рекурсивно для любого хэша:

class Hash
  def symbolize_keys
    self.is_a?(Hash) ? Hash[ self.map { |k,v| [k.respond_to?(:to_sym) ? k.to_sym : k, v.is_a?(Hash) ? v.symbolize_keys : v] } ] : self
  end
end
0 голосов
/ 02 августа 2017

В ruby ​​я считаю, что это самый простой и понятный способ превратить строковые ключи в хешах в символы:

my_hash.keys.each { |key| my_hash[key.to_sym] = my_hash.delete(key)}

Для каждого ключа в хеше мы вызываем delete для него, который удаляет его из хеша (также delete возвращает значение, связанное с удаленным ключом ), и мы немедленно устанавливаем его равным символизированному ключу .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...