创建一个哈希,其中键是字符串,值是数字

时间:2015-07-18 17:03:11

标签: ruby

我有一个数组:

["Melanie", "149", "Joe", "2", "16", "216", "Sarah"]

我想创建一个哈希:

{"Melanie"=>[149], "Joe"=>[2, 16, 216] "Sarah"=>nil}

当键和值在同一个数组中时,如何实现这一目标?

所有值都是整数(尽管它们在数组中是字符串形式。)所有键都以字母开头和结尾。

5 个答案:

答案 0 :(得分:6)

您预期的哈希值无效。因此,你不可能得到你想要的东西。

从您的问题来看,期望值为数组似乎是合理的。在这种情况下,您可以这样做:

["Melanie", "149", "Joe", "2", "16", "216", "Sarah"]
.slice_before(/[a-z]/i).map{|k, *v| [k, v.map(&:to_i)]}.to_h
# => {"Melanie"=>[149], "Joe"=>[2, 16, 216], "Sarah"=>[]}

稍微修改一下,当数组长度为1时,可以让值为数字而不是数组,但这不是一个好的设计;它会引入例外。

答案 1 :(得分:2)

试试这个

def numeric?(x) 
 x.chars.all? { |y| ('0'..'9').include?(y) }
end

array = ["Melanie", "149", "Joe", "2", "16", "216", "Sarah"]
keys = array.select { |x| not numeric?(x) }

map = {}
keys.each do |k|
    from = array.index(k) + 1
    to = array.index( keys[keys.index(k) + 1] )
    map[k] = to ? array[from...to] : array[from..from]
end

p map

<强>输出:

{"Melanie"=>["149"], "Joe"=>["2", "16", "216"], "Sarah"=>[]}
[Finished in 0.1s]

答案 2 :(得分:2)

这是另一种方式:

arr = ["Melanie", "149", "Joe", "2", "16", "216", "Sarah"]

class String
  def integer?
    !!(self =~ /^-?\d+$/)
  end
end

Hash[*arr.each_with_object([]) { |s,a| s.integer? ? a[-1] << s.to_i : a<<s<<[] }].
  tap { |h| h.each_key { |k| h[k] = nil if h[k].empty? } }
  #=> {"Melanie"=>[149], "Joe"=>[2, 16, 216], "Sarah"=>nil}  

答案 3 :(得分:1)

您的问题有三个组成部分,我将尝试单独回答。

关于存储多值映射,虽然有专门的解决方案可用,但最常见的建议是存储其值为数组的散列。也就是说,对于您的用例,您的主数据结构是一个哈希,其键是字符串,其值是整数数组。根据您所需的重复行为等,您可能希望用不同的数据结构替换值结构,可能是一组。

关于识别包含数字的字符串和不包含数字的字符串,那么,这取决于您的非数字字符串可能包含的确切内容,但一个好的起点是对数字执行正则表达式匹配。您没有指定允许的数字字符串是否表示整数,浮点数等。具体的答案可能会影响您的整体策略。不幸的是,在一般情况下,输入解析和验证是一个复杂而混乱的主题。

关于实际转换过程,我建议采用以下策略。迭代输入数组。检查每个字符串是否为数字或非数字。如果它是非数字的,则将其存储为本地的当前密钥。此外,在哈希中,创建从该键到新空数组的映射。相反,如果字符串是数字,则将其转换为数字,然后将其添加到相应键下的数组中。

答案 4 :(得分:0)

我不知道是否有一个很好的方法。我做这样的事情:

def numeric?(string)
  # `!!` converts parsed number to `true`
  !!Kernel.Float(string) 
rescue TypeError, ArgumentError
  false
end

def my_method(input_array)
  # associate values with proper key and stores result in output
  curr_key = nil
  output = {}
  input_array.each do |e|
    if !numeric?(e)
      output[e] = []
      curr_key = e
    else 
      # use Float if values may be floating-point
      output[curr_key] << Integer(e, 10)
    end
  end

  output.each do |k, v|
      output[k] = v.empty? ? nil : v
  end

  output
end

numeric方法的来源。