【问题标题】:Having trouble adding new elements to my hash (Ruby)无法将新元素添加到我的哈希 (Ruby)
【发布时间】:2021-09-15 05:17:18
【问题描述】:

Ruby 新手,一般编码新手... 我正在尝试将新元素添加到我的哈希中,并在必要时增加值。所以我使用了 Hash.new(0) 并尝试使用“+=”符号添加新值,但是当我这样做时,我收到一条错误消息 -

"/tmp/file.rb:6:in `+': String can't be coerced into Integer (TypeError)
    from /tmp/file.rb:6:in `block in stockList'
    from /tmp/file.rb:3:in `each'
    from /tmp/file.rb:3:in `each_with_index'
    from /tmp/file.rb:3:in `stockList'
    from /tmp/file.rb:24:in `<main>'
"

这是我的代码:

def stockList(stock, cat)
  hash = Hash.new(0)
  stock.each_with_index do |word, i|
    if cat.include?(word[i])
      char = word[i]
      hash[char] += num(word)  
    end
  end
  new_arr = []
  hash.each do |k, v|
    new_arr.push(k,v)
  end
  return new_arr
end
    
def num(word)
  nums = "1234567890"
  word.each_char.with_index do |char, i|
    if nums.include?(char)
      return word[i..-1]
    end
  end
end
puts stockList(["ABAR 200", "CDXE 500", "BKWR 250", "BTSQ 890", "DRTY 600"], ["A", "B"])

有人知道为什么会这样吗?

这是一个代码战挑战——我基本上得到了两个数组,旨在返回一个字符串,该字符串将与以第二个数组中列出的字母开头的单词相关联的数字相加。

对于这个输入,我打算返回“ (A : 200) - (B : 1140) ”

【问题讨论】:

  • 您到底想得到什么结果?我已经在您的代码中突出显示了一些奇怪的东西,但是如果不了解您的目标就很难给您指示 - 而且仅从代码中很难获得。
  • 哦!好吧,我现在明白了……对,对,对……因为当我添加到哈希中时……然后我会在必要时尝试将两个数字相加。好,知道了。谢谢!!
  • 在您添加解释后,我明白您为什么尝试使用 word[i],而不是整个单词作为哈希键。不过,这是一个逻辑错误:您不想在每一步都移动字母索引。用示例更新了我的答案。

标签: ruby hash


【解决方案1】:

触发此错误的特定问题是您的def num(word) 本质上是一个无操作,返回单词而不做任何更改。

但你实际上并不需要这个函数:this...

word.delete('^0-9').to_i

... 将去除所有非数字字符的单词返回给您,并将其转换为整数。

请注意,如果没有 to_i,您仍然会收到“无法将字符串强制转换为整数”错误:Ruby 不像 JavaScript 那样宽容,并试图保护您免受可能令您惊讶的结果的影响。

这是一个代码战挑战——我基本上得到了两个数组,我 意味着返回一个字符串,该字符串添加了与 以第二个数组中列出的字母开头的单词。

对于这个输入,我打算返回“ (A : 200) - (B : 1140) ”

这是到达那里的一种方式:

def stockList(stock, cat)
  hash = Hash.new(0)
  stock.each do |word|
    letter = word[0]
    if cat.include?(letter)
      hash[letter] += word.delete('^0-9').to_i
    end
  end

  hash.map { |k, v| "#{k}: #{v}" }
end

除了类型转换之外,这里还有另一个区别:始终选择单词的首字母。使用您的代码...

stock.each_with_index do |word, i|
if cat.include?(word[i])
  char = word[i]

...您实际上取了第一个股票代码的第一个字母,第二个股票代码的第二个字母等等。除非您的结果依赖于索引,否则不要使用索引。

【讨论】:

    【解决方案2】:

    您的直接问题是num(word) 返回一个字符串,而字符串不能添加到hash[char] += num(word) 行中的数字。您可以根据问题使用.to_i.to_f 转换数值的字符串表示形式。

    对于整体问题,我认为您增加了太多复杂性。问题的结构是:

    • 创建一个存储对象来统计结果。
    • 对于每个包含股票及其相关数值(价格?数量?)的字符串,将字符串拆分为两个标记。
    • 如果股票名称的第一个字符是目标值之一, 更新相应的计数。这需要从字符串转换为整数。
    • 返回最终计数。

    一个小的改进是使用Set 作为目标值。这将检查包含的工作从 O(目标数量)减少到 O(1)。只有两个目标,改进可以忽略不计,但如果股票和目标列表的增加超出了小的测试用例问题,这将是有用的。

    我做了一些重命名,希望通过更具描述性使事情更清晰。不用多说,这里是 Ruby:

    require 'set'
    
    def get_tallies(stocks, prefixes)
      targets = Set.new(prefixes)    # to speed up .include? check below
      tally = Hash.new(0)
      stocks.each do |line|
        name, amount = line.split(/ +/)   # one or more spaces is token delimiter
        tally[name[0]] += amount.to_i if targets.include?(name[0])  # note conversion to int
      end
      tally  
    end
    
    stock_list = ["ABAR 200", "CDXE 500", "BKWR 250", "BTSQ 890", "DRTY 600"]
    prefixes = ["A", "B"]
    p get_tallies(stock_list, prefixes)
    

    打印出来的

    {"A"=>200, "B"=>1140}
    

    但可以随意格式化。

    【讨论】:

      【解决方案3】:
      stock = ["ABAR 200", "CDXE 500", "BKWR 250", "BTSQ 890", "DRTY 600"]
      cat   = ["A", "B"]
      

      我同意您的决定,即使用 Hash::new 的形式创建一个哈希 h,该哈希带有一个参数(“默认值”),当 h 没有键 kh[k] 返回该参数.作为第一步,我们可以编写:

      h = stock.each_with_object(Hash.new(0)) { |s,h| h[s[0]] += s[/\d+/].to_i }
        #=> {"A"=>200, "C"=>500, "B"=>1140, "D"=>600}
      

      那么Hash#slice就可以用来提取想要的键值对了:

      h = h.slice(*cat)
        #=> {"A"=>200, "B"=>1140}
      

      此时,您已经获得了以任何您喜欢的方式显示结果所需的所有信息。例如,

      " " << h.map { |k,v| "(#{k} : #{v})" }.join(" - ") << " " 
        #=> " (A : 200) - (B : 1140) "
      

      如果h.slice(*cat) 之前的hh.slice(*cat) 大,您可以通过编写以下代码来减少内存需求并可能加快速度。

      require 'set'
      
      cat_set = cat.to_set
        #=> #<Set: {"A", "B"}>
      h = stock.each_with_object(Hash.new(0)) do |s,h|
        h[s[0]] += s[/\d+/].to_i if cat_set.include?(s[0])
      end
        #=> {"A"=>200, "B"=>1140}
      

      【讨论】:

        猜你喜欢
        • 2012-11-08
        • 1970-01-01
        • 2015-12-03
        • 1970-01-01
        • 1970-01-01
        • 2017-04-12
        • 1970-01-01
        • 2015-04-19
        • 2021-03-30
        相关资源
        最近更新 更多