Reputation: 2532
Short version: a different way to "round" numbers to user-friendly values without .round/.floor/.ceil.
Long boring version: Imagine the following conversations between a salesperson and clients:
Salesperson: how much would you pay for product X? Small timer: $15 SP: I can sell it to you at $50 ST: OK, I can live with that.
Had the salesperson said $100 the small timer would have said nah can’t afford it. And obviously he can’t just give it away for free because the salesperson isn’t a charity.
Then again with an average guy:
Salesperson: how much would you pay for product X? Average guy: don’t know...$120? SP: nah $200 is the minimum we’d sell for. AG: ok fine.
Then the big daddy comes in:
Salesperson: how much would you like to spend today sir? Big daddy: about $1200? SP: why not $1500? Big daddy: yeah let’s do $1500. SP: why not $1650? Big daddy: we might as well do $2000. SP: thank you for your business sir!
Yes, we do know who’s who, as in about how much money the customer may have, eg for a big guy we know he has around $2000-$5000 on him.
So I am looking for a way to round product prices in a smart but sensitive way as follows:
15 -> 50 #!
23 -> 50
51 -> 100
71 -> 100
109 -> 100
132 -> 150
124 -> 150 #!
173 -> 200
399 -> 400
549 -> 500
1231 -> 1500 #!
2761 -> 3000
3104 -> 3000
3249 -> 3500 #!
Basically round the prices up or down to make them user-friendly but without deviating that much from common sense...
class Price
def initialize(s = 0) # possibly add customer “size”?
@price = s
end
# operations
def inc_to(x)
@price = [@price, x].flatten.max
self
end
def dec_to(x)
@price = [@price, x].flatten.min
self
end
def inc_with(x)
@price+=x
self
end
def dec_by(x)
@price = @price - x
self
end
def avg(x)
arr = [@price, x]
@price = arr.inject{ |sum, el| sum + el }.to_f / arr.size
self
end
def round
#@price = ?
self
end
# getters
def value
@price
end
def to_i
@price.to_i
end
def to_f
@price.to_f
end
end
I've tried writing this example class but can't seem to pull a nice .round method, will appreciate any input.
Price.new(15).inc_to(1000).dec_to(700).avg(100).inc_to(200).inc_to(400).dec_to(351).inc_with(48).value # .round.to_i
Upvotes: 0
Views: 598
Reputation: 121010
It’s not possible to handle the input as you want with the generic rounding method because of contradictory rules (you want 51 to be “rounded” to 100 and others floored down.)
I would go with producing a hash or Range
→ Price
pairs:
rounds = {
(0..50) => 50,
(51..110) => 100,
(111..165) => 150,
(166..220) => 200,
...
(700..1200) => 1000,
(1201..1600) => 1500,
...
(4200..7000) => 5000
}
and then just do detect
:
rounds.detect { |range, _| range === price }.last
Upvotes: 2