繁体   English   中英

有没有办法将数组的元素与 Ruby 中散列的键匹配?

[英]Is there a way to match the elements of an array to the keys of a hash in Ruby?

我目前是一名学生。 这是作业的问题之一:

过敏测试会产生一个单一的数字分数,其中包含有关该人(他们接受测试的)所有过敏的信息。 测试的项目(及其价值)列表是:

  • 鸡蛋 (1)
  • 花生 (2)
  • 贝类 (4)
  • 草莓 (8)
  • 西红柿 (16)
  • 巧克力 (32)
  • 花粉 (64)
  • 猫 (128)

因此,如果汤姆对花生和巧克力过敏,他的得分为 34。

编写一个程序,根据一个人的分数可以告诉他们:a) 他们是否对给定的项目过敏 b) 过敏的完整列表。

现在我的代码是:

#A single numeric score is given, which is the sum of the combination of any item above 
#When there is only ONE item, the score can be: 1, 2, 4, 8, 16, 32, 64 or 128
#when TWO items, the score can be: (1 + 2 =) 3, (1+ 4 =) 5, (1 + 8 =) 9, 17, 33 , 65 , 129..., 192
#When THREE items: 7, 11, 19, 35, 67, 131 ...., 224
#....
#When EIGHT items : 255
    
#Does order matter in this case? No. use combination

#Choose a do/while loop, given the numbers the user must be allergic to something no matter what


allergens = {
        "cats" => 1,
        "pollen" => 2,
        "chocolate" => 4,
        "tomatoes" => 8,
        "strawberries" => 16,
        "shellfish" => 32,
        "peanuts" => 64,
        "eggs" => 128,
    }

score = [1, 2, 4, 8, 16, 32, 64, 128]
num_of_allergens = 1

puts "Please enter your given score: "
total_score = gets.chomp.to_i

loop do
    a1 = score.combination(num_of_allergens).to_a
    a2 = a1.map{|i| i.inject(:+)}
    if a2.include? total_score
        puts "You are allergic to: "
        a3 = a2.find_index(total_score)
        a4 = a1[a3]
        puts a4.map{|alrg| allergens.key(alrg)}
        break
    end
    if num_of_allergens > 255 || num_of_allergens < 1 
        puts "Please enter a valid number."
        break
    end
    num_of_allergens += 1
end

我想要驱动的是我想将 a4 与过敏原散列匹配,以便最终以散列的形式打印出键值对来指定过敏原(num_of_allergens 和 total_score 是固定的,现在是输入) . 这可能吗?

PS 鉴于 hash(2^0, 2^1 .... ,2^7) 值的特殊性,我的一位同学想出了使用这个循环的想法,如下所示:

if hash.each do |k,v|
  if score % value != score
    some_arr << (k,v)
    update score
  end
end 

这应该是解决问题最直接、最简洁的方法,但仍需要一点时间来解决问题。 任何人都可以请给我一些指示吗? 谢谢!!

我编辑了帖子,我刚刚设法拿到了钥匙,但现在还好

请注意每个过敏基因的分数如何是 2 的幂。您可以利用它来计算偏移量以查找过敏原:

allergens = %w[eggs peanutes shellfish strawberries tomatoes chocolate pollen cats]

score = 34 # peanuts and chocolate
puts "Your score is: #{score}"
digits = score.digits(2)
digits.each_with_index do |digit, index|
  next if digit == 0

  puts "You are allergic to #{allergens[index]}"
end

所以一步一步:

%w[]是创建字符串数组的简写

数组中每个过敏基因的索引(从 0 开始)可用于计算其分数:

score_of_allergene = 2 ** index_of_allergene

人的分数可以转换为二进制表示,作为数字数组:

score.digits(2) # 2 => base 2 (binary) => [0, 1, 0, 0, 0, 1]

现在,每个1的位置对应于该人对其产生反应的过敏基因, 0对应于该人未对其做出反应的过敏基因。 所以,当我们循环所有的标志,我们可以跳过0使用next if flag == 0和打印所有其他的人。

您可以检查:

(1..allergens.size).each { |n| p (allergens.values.sum - allergens.values.reverse.first(n).sum) }
# 127
# 63
# 31
# 15
# 7
# 3
# 1
# 0

并发现一旦结果为正,您就可以以相反的顺序从分数中减去值:

total_score = 191

res = allergens.to_a.reverse.each_with_object([]) do |(k, v), res|
    tmp = total_score - v
    if tmp >= 0
        total_score = tmp
        res << k
    end
end

res #=> ["eggs", "shellfish", "strawberries", "tomatoes", "chocolate", "pollen", "cats"]

检查结果:

res.sum { |k| allergens[k] }
#=> 191

假设 Lola 被发现对花粉和贝类过敏。 她对花粉的过敏对她的过敏评分有2分:

score = allergens["pollen"]
  #=> 2

让我们看看代表整数2的位:

nbits = score.bit_length
  #=> 2
nbits.times.map { |i| score[i] }
  #=> [0, 1]

这意味着

0*(2**0) + 1*(2**1) #=> 2

请参阅Integer#bit_lengthInteger#[]

现在让我们看看她的贝类分数,忘记她的花粉过敏。

score = allergens["shellfish"]
  #=> 32
nbits = score.bit_length
  #=> 6 
nbits.times.map { |i| score[i] }
  #=> [0, 0, 0, 0, 0, 1]

我们看到

0*(2**0) + 0*(2**1) + 0*(2**2) + 0*(2**3) + 0*(2**4) + 1*(2**5)
  #=> 32

因为每个过敏原都被分配了一个分数,该分数是2的幂,分数的一位等于1 ,其余位等于 0。 具体来说,如果分数等于2**n ,则等于1是第n+1个有效位。

现在让我们计算 Lola 的总分:

score = allergens["pollen"] + allergens["shellfish"]
  #=> 34
nbits = score.bit_length
  #=> 6 
nbits.times.map { |i| score[i] }
  #=> [0, 1, 0, 0, 0, 1]

请注意,我们可以改为写

score = allergens["pollen"] | allergens["shellfish"]
  #=> 34

整数#| .

我们首先需要编写一个方法,根据一个人的总分确定他们是否对特定的过敏原过敏。

第一步,创建一个由常量保存的新散列,将每个过敏原映射到 2 的幂,对应于总分中表示过敏原的位。

ALLERGEN_TO_BIT = allergens.transform_values do |n|
  n.bit_length-1
end
  #=> {"cats"=>0, "pollen"=>1, "chocolate"=>2, "tomatoes"=>3,
  #    "strawberries"=>4, "shellfish"=>5, "peanuts"=>6, "eggs"=>7} 

请参阅Hash#transform_values

我们现在可以编写方法。

def allergic_to?(score, allergen)
  score[ALLERGEN_TO_BIT[allergen]] == 1
end
score = 34
allergic_to?(score, "pollen")
  #=> true
allergic_to?(score, "shellfish")
  #=> true
allergic_to?(score, "cats")
  #=> false

现在转到第二个任务:给定总分,返回该人过敏的过敏原数组。

def allergic_to(score)
  ALLERGEN_TO_BIT.keys.select do |allergen|
    score[ALLERGEN_TO_BIT[allergen]] == 1
  end
end
allergic_to(34)
  #=> ["pollen", "shellfish"] 
allergic_to(38)
  #=> ["pollen", "chocolate", "shellfish"] 
allergic_to(73)
  #=> ["cats", "tomatoes", "peanuts"] 

注意

ALLERGEN_TO_BIT.keys 
  #=> ["cats", "pollen", "chocolate", "tomatoes", "strawberries",
  #    "shellfish", "peanuts", "eggs"]

假设我们要计算

allergic_to(10_000)
  #=> ["strawberries"] 

然而,这是一种误导,因为10000不是一个有效的分数。 最小和最大有效分数被视为介于01+2+4+...+128 请注意,这些限制之间的任何整数都是有效分数,因为它等于此范围内某些不同整数集合的 2 的幂之和。

1+2+4+...+128等于几何级数的总和,等于1 2*(128)-1

因此,我们可以构建一种方法来检查声称的分数是否确实有效。

def valid_score?(score)
  score.between?(0, 2*(2**ALLERGEN_TO_BIT.values.max)-1)
end
valid_score?(-1)
  #=> false
valid_score?(0)
  #=> true
valid_score?(38)
  #=> true
valid_score?(255)
  #=> true
valid_score?(256)
  #=> false

1.我总是忘记几何级数的公式,但我记得它是如何导出的: t = 1+2+4+...+128; 2*t = 2+4+...+128+2*(128); t = 2*tt = 2*(128)-1 t = 1+2+4+...+128; 2*t = 2+4+...+128+2*(128); t = 2*tt = 2*(128)-1 t = 1+2+4+...+128; 2*t = 2+4+...+128+2*(128); t = 2*tt = 2*(128)-1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM