Подтвердить что ты не робот

Сжатие хэша в строку в Ruby

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

Например, print {:a => :b, :c => :d}.flatten('=','&') должен печатать a=b&c=d

Я написал код для этого, но мне было интересно, есть ли более простой способ:

class Hash
  def flatten(keyvaldelimiter, entrydelimiter)
    string = ""
    self.each do
      |key, value|
      key = "#{entrydelimiter}#{key}" if string != "" #nasty hack
      string += "#{key}#{keyvaldelimiter}#{value}"  
    end
    return string
  end
end

print {:a => :b, :c => :d}.flatten('=','&') #=> 'c=d&a=b'

Спасибо

4b9b3361

Ответ 1

Я бы не переопределял .flatten, который уже определен:

Возвращает новый массив, который является одномерное сглаживание этого хэш. То есть для каждого ключа или значения это массив, извлекать его элементы в новый массив. В отличие от Array # flatten, этот метод не по умолчанию рекурсивно выравнивается. Если необязательный аргумент уровня определяет уровень рекурсии к сплющиванию.

Это самый простой способ сделать это, о котором я знаю:

{:a => 100, :b => 200}.map{|k,v| "#{k}=#{v}"}.join('&')
# => "a=100&b=200"

Ответ 2

Небольшое изменение версии @elektronaut:

Вместо |k, v| вместо |k, v| можно разместить только |e|, и в этом случае e представляет собой массив из двух элементов, и вы можете вызвать e.join('='). В целом у вас есть что-то вроде

class Hash
  def join(keyvaldelim=$,, entrydelim=$,) # $, is the global default delimiter
    map {|e| e.join(keyvaldelim) }.join(entrydelim)
  end
end

{a: 100, b: 200}.join('=', '&') # I love showing off the new Ruby 1.9 Hash syntax
# => 'a=100&b=200'

Ответ 3

Ну, вы можете сделать это со стандартными методами и массивами:

class Hash
  def flatten(keyvaldelimiter, entrydelimiter)
    self.map { |k, v| "#{k}#{keyvaldelimiter}#{v}" }.join(entrydelimiter)
  end
end

Вы также можете быть заинтересованы в Rails to_query method.

Кроме того, вы можете написать "#{k}#{keyvaldelimiter}#{v}" как k.to_s + keyvaldelimiter + v.to_s...

Ответ 4

Если вы пытаетесь создать строку запроса url, вам, безусловно, следует использовать такой метод, как activesupport to_param (с псевдонимом to_query). Представьте себе проблемы, если у вас есть знак амперсанда или знак равенства в самих данных.

to_query заботится об экранировании:

>> require 'active_support/core_ext/object'
>> {'a&' => 'b', 'c' => 'd'}.to_query
>> => "a%26=b&c=d"

ИЗМЕНИТЬ

@fahadsadah делает хороший вывод о том, что не хочет загружать Rails. Даже active_support/core_ext/object будет загружать 71 файл. Это также обезьяна-исправляет основные классы.

Легкое и чистое решение:

require 'rack'  # only loads 3 files
{'a&' => 'b', 'c' => 'd'}.map{|pair|
  pair.map{|e| Rack::Utils.escape(e.to_s) }.join('=')
}.join('&')
# => "a%26=b&c=d"

Важно выйти, иначе операция не будет обратимой.

Ответ 5

Не уверен, есть ли встроенный способ, но здесь есть более короткий код:

class Hash
  def flatten(kvdelim='', entrydelim='')
    self.inject([]) { |a, b| a << b.join(kvdelim) }.join(entrydelim)
  end
end

puts ({ :a => :b, :c => :d }).flatten('=', '&') # => a=b&c=d

Ответ 6

Как получить его в формате JSON. Таким образом, формат понятен.

Есть много инструментов JSON для рубинов. Тем не менее, они никогда не пробовали. Но тогда результат, конечно, будет скользить в javascript и т.д. Вероятно одна строка.

Большая экономия, хотя и будет в документации, в том, что вам понадобится гораздо меньше.