Find the specific number from Array.collect [closed] - ruby

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I want to find out what's the first, the second, and the third result, so that I can do if firstnumber==secondnumber && secondnumber==thirdnumber. How could I find those numbers on the results?
numbers = 3.times.map { Random.new.rand(0..10000) }
prizes = numbers.map do |x|
case x
when 1..3000
[ '7', 10000 ]
when 3001..6000
[ "Cherries", 500 ]
when 6001..10000
[ "Diamond", 400 ]
end
end
puts "Your results are: #{prizes.collect { |p| p[0] }.join(", ")}!
I tried to use p[0][0], but it gives the first letter instead.

Say if:
results = prizes.collect { |p| p[0] } #=> ["Diamond", "Cherries", "7"]
Then do the following to get at each result:
results[0] #=> "Diamond"
results[1] #=> "Cherries"
results[2] #=> "7"
You could also use results.first to get the first element. If you happen to be working in Rails you can even do the following:
results.second #=> "Cherries"
results.third #=> "7"

Here's a fine way to do this:
numbers = 3.times.map { Random.new.rand(0..10000) }
prizes = numbers.map do |x|
case x
when 1..3000
{ name: '7', val: 10000 }
when 3001..6000
{name: "Cherries", val: 10000 }
when 6001..10000
{name: "Diamond", val: 400 }
end
end
# You could replace 'map' with 'collect' here and have the same results
prizes_string = prizes.map { |p| "#{p[:name]}: #{p[:val]}" }.join(" and ")
puts "Your results are: #{prizes_string}!"

Related

How to calculate percentage of sum hash value in ruby [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I have static json file which contains:
{
"homes": {
"person_a": "windows+tables",
"person_b": "lights+tables",
"person_c": "doors+curtains"
}
}
The application should, for each request, calculate quotes for the 3 insurers. The business requirement is as follows:
The quote is a 10% of the rate if 2 covers are matched or 20% if just 1 cover is matched and that is the biggest requested, 25% if it is the second biggest or 30% if is the third.
the request from user is as follow
{:curtains=>20, :tables=>30, :windows=>50}
The system should not return a quote if the value is zero(0)
The application will then calculate the following quotes:
person_a: 8 (10% of 80 (two matches on windows and tables))
person_b: 7.5 (25% of 30 (one match on contents, the 2nd biggest cover))
insurer_c: 6 (30% of 20 (one match on curtains, the 3rd biggest cover)
This is my solution:
require_relative './rules'
module Coverage
class CalculateQuotes
def initialize(quotes)
#quotes = quotes
end
def get_rates
result = []
#insurer = Coverage::Rules.parse_file ## which will give {
#"insurer_rates": {
#"person_a": "windows+tables",
# "person_b": "lights+tables",
#"person_c": "doors+curtains"
# }}
#insurer[:insurer_rates].each do |k, v|
#match_covers = match_cover(v.split("+"))
result << [k, calculate_rate ]
end
end
def match_cover(covers)
covers = covers.map { |x| x.to_sym }
#quotes.select { |k,v| covers.include?(k) }
end
def calculate_rate
premium = 0.0
persentage = get_percentage_by_match_covers
#match_covers.values.each do |v|
premium += v * persentage
end
premium == 0 ? nil : premium
end
def get_percentage_by_match_covers
if #match_covers.size == 2
0.1
elsif #match_covers.size == 1
only_1_match_covers
else
0
end
end
def only_1_match_covers
index = position_of_customer_request
case index
when 0
0.2
when 1
0.25
when 2
0.3
else
raise StandardError
end
end
def position_of_customer_request
(#quotes.to_a.reverse).index(#match_covers.to_a.flatten)
end
end
end
request = {:windows=>50, :contents=>30, :engine=>20}
Coverage::CalculateQuotes.new(request).get_rates
Please help me on How can I make it better calculation and code with SOLID ruby principles??
Data
double_quote_rate = 0.1
single_quote_rate = [0.3, 0.25, 0.2]
request = {:curtains=>20, :tables=>30, :windows=>50}
Code
The key is to create a hash that maps sets of products into their computed values.
The first step is to create the key-value pairs where the key is a set containing a single product:
require 'set'
h = single_quote_rate.zip(request.sort_by(&:last)).
each_with_object({}) { |(rate, (product, score)),h|
h[[product].to_set] = rate*score }
#=> {#<Set: {:curtains}>=>6.0, #<Set: {:tables}>=>7.5,
# #<Set: {:windows}>=>10.0}
Note that the values in single_quote_rate are ordered largest to smallest. The intermediate calculation is as follows:
single_quote_rate.zip(request.sort_by(&:last))
#=> [[0.3, [:curtains, 20]], [0.25, [:tables, 30]],
# [0.2, [:windows, 50]]]
Now add all combinations of two products:
request.to_a.combination(2).each { |(product1, score1),(product2,score2)|
h[[product1,product2].to_set] = double_quote_rate*(score1+score2) }
h #=> {#<Set: {:curtains}>=>6.0,
# #<Set: {:tables}>=>7.5,
# #<Set: {:windows}>=>10.0,
# #<Set: {:curtains, :tables}>=>5.0,
# #<Set: {:curtains, :windows}>=>7.0,
# #<Set: {:tables, :windows}>=>8.0}
Here the first calculation is as follows:
enum = request.to_a.combination(2)
#=> #<Enumerator: [[:curtains, 20], [:tables, 30],
# [:windows, 50]]:combination(2)>
We can convert this enumerator to an array to see the three elements (arrays) that will be passed to the block.
enum.to_a
#=> [[[:curtains, 20], [:tables, 30]],
# [[:curtains, 20], [:windows, 50]],
# [[:tables, 30], [:windows, 50]]]
The block variables are assigned as follows:
(product1, score1),(product2,score2) = enum.next
#=> [[:curtains, 20], [:tables, 30]]
product1
#=> :curtains
score1
#=> 20
product2
#=> :tables
score2
#=> 30
Breaking up arrays into their component elements is called array decompostion.
For convenience assign the keys of request to a variable:
keys = request.keys
#=> [:curtains, :tables, :windows]
Example
hash = { "homes": { "person_a": "windows+tables",
"person_b": "lights+tables",
"person_c": "doors+curtains" } }
hash[:"homes"].transform_values do |s|
h[s.split('+').map(&:to_sym).select { |s| keys.include?(s) }.to_set]
end
#=> {:person_a=>8.0, :person_b=>7.5, :person_c=>6.0}
An example calculation of the key to use to obtain the desired value of h is as follows:
s = "lights+tables"
a = s.split('+')
#=> ["lights", "tables"]
b = a.map(&:to_sym)
#=> [:lights, :tables]
c = b.select { |s| keys.include?(s) }
#=> [:tables]
d = c.to_set
#=> #<Set: {:tables}>
h[d]
#=> 7.5

Best combination based in rules [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
Which combination of five entries has the largest combined scores subject to the condition?
If the dataset is not huge, here you go (possibly quite inefficient):
data =
%|Derek Aufderhar, 2134, 1
Hadley Kuhn, 2044, 0
Myrtie Lueilwitz, 2207, 2
Mitchell Schiller, 2036, 2
Javier Walter MD, 2485, 4
Waino Leuschke, 2486, 2
Ariel Jacobson, 2015, 3
Melvin Bailey, 2485, 0
Dovie Emmerich, 2383, 4
Adrian Stroman Jr., 2180, 1
Helen Douglas, 2352, 4
Yessenia O’Reilly, 2247, 2|
# unnecessary: transform to hash for clarity
values =
data.
split($/).
map { |e| e.split(',') }.
map { |name, elo, score| {name: name, elo: elo.to_i, score: score.to_i } }
# find the top
values.
combination(5).
reject { |data| data.map { |e| e[:elo] }.inject(:+) > 11_000 }.
max { |data| data.map { |e| e[:score] }.inject(:+) }
#⇒ [{:name=>"Yessenia O'Reilly", :elo=>2247, :score=>2},
# {:name=>"Helen Douglas", :elo=>2352, :score=>4},
# {:name=>"Adrian Stroman Jr.", :elo=>2180, :score=>1},
# {:name=>"Ariel Jacobson", :elo=>2015, :score=>3},
# {:name=>"Mitchell Schiller", :elo=>2036, :score=>2}]
Code
def best_five(players, max_elo)
players.combination(5).with_object({ names:[], tot_scores: -1 }) do |arr, best|
names, elos, scores = arr.map(&:values).transpose
best.replace({ names: names, tot_scores: scores.sum }) unless
elos.sum > max_elo || scores.sum <= best[:tot_scores]
end
end
Here players is an array of hashes, each with keys :name, :elo and score, where the value of :name is a string and values of the other two keys are integers.
Example
players =<<_
Derek Aufderhar, 2134, 1
Hadley Kuhn, 2044, 0
Myrtie Lueilwitz, 2207, 2
Mitchell Schiller, 2036, 2
Javier Walter MD, 2485, 4
Waino Leuschke, 2486, 2
Ariel Jacobson, 2015, 3
Melvin Bailey, 2485, 0
Dovie Emmerich, 2383, 4
Adrian Stroman Jr., 2180, 1
Helen Douglas, 2352, 4
Yessenia O’Reilly, 2247, 2
_
It is convenient to convert this string to a hash, both to address the current problem and to perform other operations with the data.
players_by_name = players.each_line.with_object({}) do |line, h|
name, elo, score = line.split(',')
h[name] = { name: name, elo: elo.to_i, score: score.to_i }
end
#=> {"Derek Aufderhar" =>{:name=>"Derek Aufderhar", :elo=>2134, :score=>1},
# "Hadley Kuhn" =>{:name=>"Hadley Kuhn", :elo=>2044, :score=>0},
# ...
# "Yessenia O’Reilly"=>{:name=>"Yessenia O’Reilly", :elo=>2247, :score=>2}}
We may now compute the best five for max_elo = 11000:
best = best_five(players_by_name.values, 11000)
#=> {:names=>["Myrtie Lueilwitz", "Mitchell Schiller", "Ariel Jacobson",
# "Dovie Emmerich", "Helen Douglas"],
# :tot_scores=>15}
To retrieve information for these five players we compute the following:
a = players_by_name.values_at(*best[:names])
#=> [{:name=>"Myrtie Lueilwitz" , :elo=>2207, :score=>2},
# {:name=>"Mitchell Schiller", :elo=>2036, :score=>2},
# {:name=>"Ariel Jacobson" , :elo=>2015, :score=>3},
# {:name=>"Dovie Emmerich" , :elo=>2383, :score=>4},
# {:name=>"Helen Douglas" , :elo=>2352, :score=>4}]
We already know the scores sum to 15. As
a.map { |h| h[:elo] }.sum
#=> 10993
we see that the combined ELO limit is not exceeded.
Array#sum made its debut in Ruby v2.4.

error adding ruby code on a structure [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I have a structure defined in 'strct'. Its possible to add some ruby code like the next example?
def strct(i)
{
"mwdata": [
i.times do //incorrect
{
"mwtype": "cell",
"mwsize": [
1,
3
],
"mwdata": [
10,
23,
199
]
}
end //incorrect
]
}
end
You can multiply arrays by using *, but this will create an Array of references to the same Hash object, changing one, changes all of them. (as #mudasobwa pointed out in the comments)
def strct(i)
{ "mwdata": [ {...} ] * i }
end
It's also possible to use tap:
def strct(i)
{ "mwdata" => [].tap do |array|
i.times do
array << { .... }
end
end
}
end
Or inject:
def strct(i)
{ "mwdata" => 1.upto(i).inject([]) do |array|
array << { .... }
end
}
end
Note
I understand the reason for this question, as I have often found myself doing something like:
def strct(i)
result = { "foo" => [] }
i.times do
result["foo"] << "Something #{i}"
end
result
end
Quick googling gave me this: hash_builder.rb that works like jsonbuilder and can be used to create hash "templates".

Idiomatically removing bracketted list elements [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
How can one generate a new list has all the elements of old-list except for some parts bracketted between line where f1(start_line) is true and f2(end_line) is true
Naive code
def remove_bracketted(orig_list)
ignore_flag = false
new_list = []
orig_list.each do |v|
if f1(v)
ignore_flag = true
elsif f2(v)
ignore_flag = false
else
new_list << v unless ignore_flag
end
end
end
For instance, with the following definitions of f1 and f2
def f1(v)
v == "{"
end
def f2(v)
v == "}"
end
when run on
foo(a,b)
{
s1
s2
s3
}
bar(a,b)
{
t1
t2
t3
}
Some other text
one should get
foo(a,b)
bar(a,b)
Some other text
Kindly note that f1 and f2 can be any function of type a -> Bool where list elements are all of type a and not just comparison to an open brace and close brace.
Edit:
I was looking for a solution like this which works if there is only one such pair
new_list = old_list.take_while(not(condition1)).concat(old_list.drop_while(not(condition2)))
This might be a place where the flip-flop operator would be useful:
def val1; '{' end
def val2; '}' end
p ['a','b','{','a','}','f','d','d'].reject{|x| true if (val1==x)..(val2==x)}
#=> ["a", "b", "f", "d", "d"]
p ['a','b','{','a','}','f','d','d'].select{|x| true if (val1==x)..(val2==x)}
#=> ["{", "a", "}"]
ScriptDevil, i guess some people won't like your way of making a question so i suggest asking it somewhat politer and not offer us a 'task' like we are in class. We are here to help and you should show us what you tried yourself.
Here is a way of doing what you want.
class String
def replace_between start, ending, replace_with
gsub(/#{start}[^#{ending}]*#{ending}/m, replace_with)
end
end
txt = %[
foo(a,b)
{
s1
s2
s3
}
bar(a,b)
{
t1
t2
t3
}
Some other text
]
puts txt.replace_between '{', '}', ''
# oo(a,b)
# bar(a,b)
# Some other text

Retrieve nested hash values ruby [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I have a nested Hash like this :
{
:a=>{
:toto=>{
:foo=>10,
:bar=>11,
:baz=>12
},
:titi=>"a"
},
:b=>{
:toto=>{
:foo=>31,
:bar=>45,
:baz=>78
},
:titi=>"b"
}
}
My goal is to sum all the :baz values. I'm sure there is a beautiful way to do this in ruby. Any idea?
Thanks.
#inject is very powerful method that works for both arrays and hashes. You can walk through values of hash and sum the needed key to the total sum.
hash.inject(0) { |sum, (_,v)| sum += v[:toto][:baz] } # => 90
h = {
:a=>{
:toto=>{
:foo=>10,
:bar=>11,
:baz=>12
},
:titi=>"a"
},
:b=>{
:toto=>{
:foo=>31,
:bar=>45,
:baz=>78
},
:titi=>"b"
}
}
h.inject(0){|sum,(_,v)| sum +=v.fetch(:toto,{}).fetch(:baz,0)}
This method finds all :baz elements, regardless of their path.
h = {
:a=>{
:toto=>{
:foo=>10,
:bar=>11,
:baz=>12,
},
:titi=>"a"
},
:b=>{
:toto=>{
:foo=>31,
:bar=>45,
:baz=>78,
},
:titi=>"b",
},
}
def sum_baz(hash)
hash.values.reduce(0) do |memo, elem|
if elem.is_a?(Hash)
memo += sum_baz(elem)
memo += elem[:baz] if elem[:baz]
end
memo
end
end
sum_baz(h) # => 90

Resources