在Ruby中将哈希扁平化为字符串

Fah*_*dah 49 ruby hash

有没有办法将哈希扁平化为字符串,键和值之间有可选的分隔符,以及键/值对?

例如,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'
Run Code Online (Sandbox Code Playgroud)

谢谢

ele*_*aut 109

我不会覆盖.flatten,已经定义:

返回一个新数组,该数组是此哈希的一维展平.也就是说,对于作为数组的每个键或值,将其元素提取到新数组中.与Array#flatten不同,此方法默认情况下不会递归展平.如果可选的level参数确定了flatten的递归级别.

这是我所知道的最简单的方法:

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

  • 您可以进一步简化此操作.详情请见我的回答.要点是将`| k,v |`替换为`| e |`,它使`e`成为一个可以称为'e.join('=')`的数组. (5认同)
  • 我更喜欢 `{ a: 100, b: 200 }.map {|h| h.join '=' }.join '&'`。只是干净一点。 (2认同)

Jör*_*tag 22

@ elektronaut版本的轻微变化:

你实际上可以只放一个|e|而不是|k, v|在哪种情况下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'
Run Code Online (Sandbox Code Playgroud)

  • 我会严肃地质疑猴子补丁`Hash`是多么聪明,尤其是使用像`join`这样的非命名空间方法名称.虽然我期待很多人这样做,但我很惊讶地看到一位非常有经验的开发者提出这样的建议. (8认同)

Kel*_*vin 6

如果你想生成一个 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"
Run Code Online (Sandbox Code Playgroud)

编辑

@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"
Run Code Online (Sandbox Code Playgroud)

逃跑很重要,否则操作是不可逆的。


Ama*_*dan 5

好吧,你可以使用标准方法和数组来做到这一点:

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

您可能也对Rails to_query方法感兴趣.

此外,很明显,你可以写"#{k}#{keyvaldelimiter}#{v}"k.to_s + keyvaldelimiter + v.to_s......

  • 或者``[k,v] .join(keyvaldelimiter)`. (2认同)