[英]sort an array in ascending and descending order by the hash keys of the containing elements in Ruby
[英]Is there a way to match the elements of an array to the keys of a hash in Ruby?
我目前是一名学生。 这是作业的问题之一:
过敏测试会产生一个单一的数字分数,其中包含有关该人(他们接受测试的)所有过敏的信息。 测试的项目(及其价值)列表是:
因此,如果汤姆对花生和巧克力过敏,他的得分为 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_length和Integer#[] 。
现在让我们看看她的贝类分数,忘记她的花粉过敏。
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}
我们现在可以编写方法。
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
不是一个有效的分数。 最小和最大有效分数被视为介于0
和1+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.