Converting hash ruby objects to positive currency - ruby-on-rails

I have a hash where the keys are the months and I want to convert the objects to positive numbers AND currency.
INPUT
hash = {
12 => -5888.969999999999,
4 => -6346.1,
3 => -6081.76,
2 => -5774.799999999999,
1 => -4454.38
}
OUTPUT
hash = {
12 => 5888.96,
4 => 6346.10,
3 => 6081.76,
2 => 5774.79,
1 => 4454.38
}
#Output should be a float
Any help would be greatly appreciated.

Try
hash.transform_values{|v| v.round(2).abs()}
or
hash.update(hash){|k,v| v.round(2).abs()}

Numeric.abs() can be applied to ensure a number is positive and Float.round(2) will round a float to 2 decimal places. See ruby-doc.org/core-2.1.4/Numeric.html#method-i-abs and ruby-doc.org/core-2.2.2/Float.html#method-i-round for usage examples. Note that round() will not add trailing zeros since that does not affect numerical value, however trailing zeros can be added by formatting, for example:
hash = {
12 => -5888.969999999999,
4 => -6346.1,
3 => -6081.76,
2 => -5774.799999999999,
1 => -4454.38
}
# transform hash values
hash.each do |key, value|
hash[key] = value.abs().round(2)
end
# print the modified hash without formatting the values
hash.each do |key, value|
puts "#{key} => #{value}"
end
# prints
# 12 => 5888.97
# 4 => 6346.1
# 3 => 6081.76
# 2 => 5774.80
# 1 => 4454.38
# print hash with values formatted with precision of 2 digits
hash.each do |key, value|
puts "#{key} => #{'%.2f' % value}"
end
# prints
# 12 => 5888.97
# 4 => 6346.10
# 3 => 6081.76
# 2 => 5774.80
# 1 => 4454.38

Related

Perform arithmetic operations on string in Ruby

input: "20+10/5-1*2"
I want to perform arithmetic operations on that string how can I do it without using eval method in ruby?
expected output: 20
While I hesitate to answer an interview question, and I am completely embarrassed by this code, here is one awful way to do it. I made it Ruby-only and avoided Rails helpers because it seemed more of a Ruby task and not a Rails task.
#
# Evaluate a string representation of an arithmetic formula provided only these operations are expected:
# + | Addition
# - | Subtraction
# * | Multiplication
# / | Division
#
# Also assumes only integers are given for numerics.
# Not designed to handle division by zero.
#
# Example input: '20+10/5-1*2'
# Expected output: 20.0
#
def eval_for_interview(string)
add_split = string.split('+')
subtract_split = add_split.map{ |v| v.split('-') }
divide_split = subtract_split.map do |i|
i.map{ |v| v.split('/') }
end
multiply_these = divide_split.map do |i|
i.map do |j|
j.map{ |v| v.split('*') }
end
end
divide_these = multiply_these.each do |i|
i.each do |j|
j.map! do |k, l|
if l == nil
k.to_i
else
k.to_i * l.to_i
end
end
end
end
subtract_these = divide_these.each do |i|
i.map! do |j, k|
if k == nil
j.to_i
else
j.to_f / k.to_f
end
end
end
add_these = subtract_these.map! do |i, j|
if j == nil
i.to_f
else
i.to_f - j.to_f
end
end
add_these.sum
end
Here is some example output:
eval_for_interview('1+1')
=> 2.0
eval_for_interview('1-1')
=> 0.0
eval_for_interview('1*1')
=> 1.0
eval_for_interview('1/1')
=> 1.0
eval_for_interview('1+2-3*4')
=> -9.0
eval_for_interview('1+2-3/4')
=> 2.25
eval_for_interview('1+2*3/4')
=> 2.5
eval_for_interview('1-2*3/4')
=> -0.5
eval_for_interview('20+10/5-1*2')
=> 20.0
eval_for_interview('20+10/5-1*2*4-2/6+12-1-1-1')
=> 31.0

How to address nested array keys after grouping in Rails?

I have table called sales like this:
id customer_id product_id sales
1 4 190 100
2 4 190 150
3 4 191 200
4 5 192 300
5 6 200 400
What I'd like to do is, get a total on how many of each products have been bought by a customer. Therefor I perform a simple group by:
Sales.all.group(:customer_id, product_id).sum(:sales)
What this gives me is a hash with keys consisting of arrays with the combination of customer_id and product_id:
hash = {
[4, 190] => 250,
[4, 191] => 200,
[5, 192] => 300,
[6, 200] => 400
}
While this gives me the result, I'm now also looking to get the total sum of sales for each customer. I could of course write another query, but this feels redundant. Isn't there an easy way to do find all the hash array keys that start with [4, *] or something?
To get this value for a single value, you could do the following:
hash.select{|x| x[0] == 4}.values.sum
=> 450
But you could also transform the hash to a grouped one on the customer-ids.
hash.inject(Hash.new(0)) do |result, v|
# v will look like [[4, 190], 250]
customer_id = v[0][0]
result[customer_id] += v[1]
result
end
which you could also write as a one-liner
hash.inject(Hash.new(0)){|result, v| result[v[0][0]] += v[1]; result}
=> {4=>450, 5=>700}
Which can be further shortened when using each_with_object instead of inject (thanks to commenter Sebastian Palma)
hash.each_with_object(Hash.new(0)){|v,result| result[v[0][0]] += v[1]}
You can try following,
hash.group_by { |k,v| k.first }.transform_values { |v| v.map(&:last).sum }
# => {4=>450, 5=>300, 6=>400}
Try this:
hash.each_with_object(Hash.new(0)) do |(ids, value), result|
result[ids.first] += value
end
#=> { 4 => 450, 5 => 700 }
You could group the resulting hash based on customer id. Then sum all the values in the group:
hash = {
[4, 190] => 250,
[4, 191] => 200,
[5, 192] => 300,
[6, 200] => 400
}
hash.group_by { |entry| entry.shift.first }
.transform_values { |sums| sums.flatten.sum }
#=> {4=>450, 5=>300, 6=>400}
group_by groups the key-value pairs based on the customer id. shift will remove the key (leaving only the values), while first selects the customer id (since it is the first element in the array). This leaves you with an hash { 4 => [[250], [200]], 5 => [[300]], 6 => [[400]] }.
You then flatten the groups and sum all the values to get the sum for each costomer id.
Another approach would be to group by ID.
hash.
group_by { |(k, _), _| k }.
each_with_object(Hash.new{0}) do |(k, arr), acc|
acc[k] += arr.sum(&:last)
end
#⇒ {4=>450, 5=>700}

How to convert human readable number to actual number in Ruby?

Is there a simple Rails/Ruby helper function to help you convert human readable numbers to actual numbers?
Such as:
1K => 1000
2M => 2,000,000
2.2K => 2200
1,500 => 1500
50 => 50
5.5M => 5500000
test = {
'1K' => 1000,
'2M' => 2000000,
'2.2K' => 2200,
'1,500' => 1500,
'50' => 50,
'5.5M' => 5500000
}
class String
def human_readable_to_i
multiplier = {'K' => 1_000, 'M' => 1_000_000}[self.upcase[/[KM](?=\z)/]] || 1
value = self.gsub(/[^\d.]/, '')
case value.count('.')
when 0 then value.to_i
when 1 then value.to_f
else 0
end * multiplier
end
end
test.each { |k, v| raise "Test failed" unless k.human_readable_to_i == v }
Try something like this if you have an array of human readable numbers than
array.map do |elem|
elem = elem.gsub('$','')
if elem.include? 'B'
elem.to_f * 1000000000
elsif elem.include? 'M'
elem.to_f * 1000000
elsif elem.include? 'K'
elem.to_f * 1000
else
elem.to_f
end
end
Have a look here as well, you will find many Numbers Helpers
NumberHelper Rails.
Ruby Array human readable to actual

Convert integer to binary string, padded with leading zeros

I want to create new method Integer#to_bin that convert decimal to a binary string. The argument of #to_bin is the number of digits. The result should be padded with leading zeros to make it have that many digits.
Example:
1.to_bin(4)
#=> "0001"
1.to_bin(3)
#=> "001"
1.to_bin(2)
#=> "01"
7.to_bin(1)
#=> nil
7.to_bin
#=> "111"
etс.
What I've tried:
class Integer
def to_bin(number=nil)
if number == nil
return self.to_s(2)
else
s = self.to_s(2).size
e = number-s
one = '0'
two = '00'
three = '000'
if e==one.size
one+self.to_s(2)
elsif e==two.size
two+self.to_s(2)
elsif e==three.size
three+self.to_s(2)
end
end
end
end
How do I convert an integer to a binary string padded with leading zeros?
The appropriate way to do this is to use Kernel's sprintf formatting:
'%03b' % 1 # => "001"
'%03b' % 2 # => "010"
'%03b' % 7 # => "111"
'%08b' % 1 # => "00000001"
'%08b' % 2 # => "00000010"
'%08b' % 7 # => "00000111"
But wait, there's more!:
'%0*b' % [3, 1] # => "001"
'%0*b' % [3, 2] # => "010"
'%0*b' % [3, 7] # => "111"
'%0*b' % [8, 1] # => "00000001"
'%0*b' % [8, 2] # => "00000010"
'%0*b' % [8, 7] # => "00000111"
So defining a method to extend Fixnum or Integer is easy and cleanly done:
class Integer
def to_bin(width)
'%0*b' % [width, self]
end
end
1.to_bin(8) # => "00000001"
0x55.to_bin(8) # => "01010101"
0xaaa.to_bin(16) # => "0000101010101010"
Ruby already has a built-in mechanism to convert a number to binary: #to_s accepts a base to convert to.
30.to_s(2) # => "11110"
If you want to left-pad it with zeroes:
30.to_s(2).rjust(10, "0") => "0000011110"
You could extend this into a little method that combines the two:
class Fixnum
def to_bin(width = 1)
to_s(2).rjust(width, "0")
end
end
> 1234.to_bin
=> "10011010010"
> 1234.to_bin(20)
=> "00000000010011010010"

Number to English Word Conversion Rails

Anybody knows the method to convert the numericals to english number words in rails?
I found some Ruby scripts to convert numbericals to english words for corresponding words.
Instead of writing a script in ruby, i feel that direct function is available.
Eg. 1 -> One, 2 -> Two.
Use the numbers_and_words gem, https://github.com/kslazarev/numbers_and_words
The humanize gem that does exactly what you want:
require 'humanize'
23.humanize # => "twenty three"
0.42.humanize(decimals_as: :digits) # => "zero point four two"
No, you have to write a function yourself. The closest thing to what you want is number_to_human, but that does not convert 1 to One.
Here are some URLs that may be helpful:
http://codesnippets.joyent.com/posts/show/447
http://raveendran.wordpress.com/2009/05/29/ruby-convert-number-to-english-word/
http://deveiate.org/projects/Linguistics/
You can also use the to_words gem.
This Gem converts integers into words.
e.g.
1.to_words # one ,
100.to_words # one hundred ,
101.to_words # one hundred and one
It also converts negative numbers.
How about this? Written for converting numbers to words in the Indian system, but can be easily modified.
def to_words(num)
numbers_to_name = {
10000000 => "crore",
100000 => "lakh",
1000 => "thousand",
100 => "hundred",
90 => "ninety",
80 => "eighty",
70 => "seventy",
60 => "sixty",
50 => "fifty",
40 => "forty",
30 => "thirty",
20 => "twenty",
19=>"nineteen",
18=>"eighteen",
17=>"seventeen",
16=>"sixteen",
15=>"fifteen",
14=>"fourteen",
13=>"thirteen",
12=>"twelve",
11 => "eleven",
10 => "ten",
9 => "nine",
8 => "eight",
7 => "seven",
6 => "six",
5 => "five",
4 => "four",
3 => "three",
2 => "two",
1 => "one"
}
log_floors_to_ten_powers = {
0 => 1,
1 => 10,
2 => 100,
3 => 1000,
4 => 1000,
5 => 100000,
6 => 100000,
7 => 10000000
}
num = num.to_i
return '' if num <= 0 or num >= 100000000
log_floor = Math.log(num, 10).floor
ten_power = log_floors_to_ten_powers[log_floor]
if num <= 20
numbers_to_name[num]
elsif log_floor == 1
rem = num % 10
[ numbers_to_name[num - rem], to_words(rem) ].join(' ')
else
[ to_words(num / ten_power), numbers_to_name[ten_power], to_words(num % ten_power) ].join(' ')
end
end
You may also want to check gem 'rupees' - https://github.com/railsfactory-shiv/rupees to convert numbers to indian rupees (e.g. in Lakh, Crore, etc)

Resources