Rounding a number to nearest fractional eighth or third in Ruby - ruby

I want to round any given number to an eighth or a third in Ruby, whichever is closest.
I'm hoping for output like 1/8 or 2/3.
I've tried the following:
scalar_in_eighths = (scalar * 8.0).round / 8.0
scalar_in_thirds = (scalar * 3.0).round / 3.0
thirds_difference = (scalar - scalar_in_thirds).abs
eighths_difference = (scalar - scalar_in_eighths).abs
compute_in_thirds = thirds_difference < eighths_difference
if compute_in_thirds
less_than_eighth = false
rounded_scalar = scalar_in_thirds
else
less_than_eighth = false
rounded_scalar = scalar_in_eighths
end
quotient, modulus = rounded_scalar.to_s.split '.'
quotient = quotient.to_f
modulus = ".#{modulus}".to_f
This works well for eights, but for numbers like 1.32 it breaks down.
Doing modulus.numerator and modulus.denominator for the fractional components will yield numbers like 6004799503160661 and 18014398509481984.
Is there a better way to solve this?

Here's one way you could write it.
Code
def closest_fraction(f,*denominators)
n, frac = denominators.map { |n| [n, round_to_fraction(f,n)] }
.min_by { |_,g| (f-g).abs }
[(n*frac).round, n, frac]
end
def round_to_fraction(f,n)
(f*n).round/n.to_f
end
Examples
closest_fraction(2.33, 3, 8)
#=> [7, 3, 2.3333333333333335]
closest_fraction(2.12, 3, 8)
#=> [17, 8, 2.125]
closest_fraction(2.46, 2, 3, 5)
#=> [5, 2, 2.5]
closest_fraction(2.76, 2, 3, 5, 7, 11, 13, 17)
#=> [47, 17, 2.764705882352941]

Related

(Ruby) First x Recursive Nums

I want to write a recursive method that returns the first num recursive numbers.
Here is my code so far:
def recursive_factorials(num)
return [1] if num == 1
arr = recursive_factorials(num-1)
arr << num * arr.last
end
Not sure what I'm doing wrong. The expected result for num = 6 is [1, 1, 2, 6, 24, 120], and I get [1, 2, 6, 24, 120, 720], so I may be close but really have no idea.
Any help would be appreciated. Also, if I am not using recursion properly please let me out.
Question is about recursion, but also you can use iteration, it's faster:
def factorials(num)
m = 1
(0...num).map {|e| e.zero? ? 1 : m *= e }
end
factorials(6)
=> [1, 1, 2, 6, 24, 120]
Or by using hash memoisation (I would say its a recursion too):
factorials = Hash.new { |h, k| h[k] = h[k-1] * k }.update(0 => 1)
factorials.values_at(*(0..5))
=> [1, 1, 2, 6, 24, 120]
Here is an example:
def recursive_factorials(num, acc = [])
acc << (num < 2 ? 1 : (num - 1) * recursive_factorials(num - 1, acc).last)
end
recursive_factorials 6
#⇒ [1, 1, 2, 6, 24, 120]
A variation of Ilya's answer:
def each_factorial
return enum_for(__method__) unless block_given?
m = 1
1.step do |i|
yield m
m *= i
end
end
each_factorial.take(6)
#=> [1, 1, 2, 6, 24, 120]

Given integers how do I find asc and desc sequences of three?

I have integers i.e. 9, 5, 4, 3, 1, 6, 7, 8. I want to return the index where a sequence of three descending or ascending integers exists. In the example above I would get indices 1 and 5. What is the ruby code for this?
def seq
array = [9,5,4,3,1,6,7,8]
array.each_with_index |val, index|
if (val < (array[index + 1]).val < (array[index + 1]).val)
puts "#{index}"
# Skip two indexes
end
end
I think the logic behind your solution is almost correct, but your syntax is pretty far off from valid Ruby.
Here are a pair of pretty verbose solutions that will (hopefully) be fairly obvious:
numbers = [9, 6, 5, 4, 3, 1, 6, 7, 8]
# Find non-overlapping sets
i = 0
until i > numbers.length - 2
a, b, c = numbers[i..i + 2]
if (a - b == b - c) && (a - b).abs == 1
puts "#{i} (#{a},#{b},#{c})"
# Skip next two indexes
i += 3
else
i += 1
end
end
# Find overlapping sets (same solution, but don't skip indexes)
(0...numbers.length - 2).each do |i|
a, b, c = numbers[i..i + 2]
if (a - b == b - c) && (a - b).abs == 1
puts "#{i} (#{a},#{b},#{c})"
end
end
Since the question is not clear enough. I will assume the question is about finding 3 ascending or descending continuous numbers. If the length of the satisfied sequence it longer than 3, e.g [2, 3, 4, 5], it returns 0 and 1.
Here is the algorithm, do list[index] - list[index - 1] for all elements, and repeat it for another time, the answer will be the index of 0 elements after the calculation.
Intuitively,
original 9, 5, 4, 3, 1, 6, 7, 8
first pass -4, -1, -1, -2, 5, 1, 1
2nd pass 3, 0, -1, 7, 4, 0 -> the answer will be the indexes of 0's, which is 1, 5
Algorithm:
lst = [9, 5, 4, 3, 1, 6, 7, 8]
lst1 = lst.each_cons(2).map{ |a, b| b-a }
lst2 = lst1.each_cons(2).map{ |a, b| b-a }
result = lst2.each_index.select{|i| lst2[i] == 0}
result = [1, 5]
Here’s a solution using each_cons(3).with_index:
[9,5,4,3,1,6,7,8].each_cons(3).with_index.select { |s, i| s[0] < s[1] && s[1] < s[2] }.map(&:last)

Calculate interquartile mean from Ruby array?

I have this array:
[288.563044, 329.835918, 578.622569, 712.359026, 866.614253, 890.066321, 1049.78037, 1070.29897, 2185.443662, 2492.245562, 4398.300227, 13953.264379]
How do I calculate the interquartile mean from this?
That Wikipedia link explains it best, but I basically need to remove the bottom and top 25% leaving only the middle 50%, of which I'll need to average the numbers.
But that's assuming the number of array items is divisible by 4. Here's how to calculate it when it's not divisible by four.
So how would I do that as well?
This is a partial solution for an array with a number of elements that is a multiple of 4. I'll put the full one when I figure it out.
arr = [288.563044, 329.835918, 578.622569, 712.359026, 866.614253, 890.066321, 1049.78037, 1070.29897, 2185.443662, 2492.245562, 4398.300227, 13953.264379].sort!
length = arr.size
mean = arr.sort[(length/4)..-(length/4+1)].inject(:+)/(length/2)
I think this is a better solution.
def interquartile_mean(array)
arr = array.sort
length = arr.size
quart = (length/4.0).floor
fraction = 1-((length/4.0)-quart)
new_arr = arr[quart..-(quart + 1)]
(fraction*(new_arr[0]+new_arr[-1]) + new_arr[1..-2].inject(:+))/(length/2.0)
end
The simple case array_size mod 4 = 0:
xs = [5, 8, 4, 38, 8, 6, 9, 7, 7, 3, 1, 6]
q = xs.size / 4
ys = xs.sort[q...3*q]
mean = ys.inject(0, :+) / ys.size.to_f
#=> 6.5
The general case (array_size >= 4):
xs = [1, 3, 5, 7, 9, 11, 13, 15, 17]
q = xs.size / 4.0
ys = xs.sort[q.ceil-1..(3*q).floor]
factor = q - (ys.size/2.0 - 1)
mean = (ys[1...-1].inject(0, :+) + (ys[0] + ys[-1]) * factor) / (2*q)
#=> 9.0
However, if you don't try to code it yourself this won't help much...
An improvement on tokland's answer that augments the Array class and fixes an edge case (method as written blows up with array size of 4).
class Array
def interquartile_mean
a = sort
l = size
quart = (l.to_f / 4).floor
t = a[quart..-(quart + 1)]
t.inject{ |s, e| s + e }.to_f / t.size
end
end

How do I loop through a set of numbers, do some addition and append to an array?

My goal here is to create an array with the sum totals of every combination of 2 numbers on a set of dice. I'm creating the beginning of a loop that adds die1[0] to die2[0..5] before going through die1[1] + die2[0..5] and so on.
I've got this code below and I'm doing something wrong. I want to be able to call specific numbers in the array, such as dieSums[4], and get one number. Any idea what i'm doing incorrectly here?
die1 = [1,2,3,4,5,6]
die2 = [1,2,3,4,5,6]
dieSums = []
count = 0
while count <= 5 do
dieSums << die1[0] + die2[count]
count += 1
puts dieSums[5]
end
A while loop, as you've written it, isn't very Rubyonic. (Rubinic?) A more idiomatic way to iterate over the elements of an array:
#!/usr/bin/ruby
die1 = [1,2,3,4,5,6]
die2 = [1,2,3,4,5,6]
dieSums = []
die1.each do |d1|
die2.each do |d2|
dieSums << d1 + d2
end
end
puts dieSums[5]
Of course, die1 and die2 are identical in this case, so you could replace die2 with die1 and it'd all work out.
You are calling puts dieSums[5] inside the loop. dieSums[5] won't exist until the last iteration. It'll work if you call it outside the loop:
die1 = [1,2,3,4,5,6]
die2 = [1,2,3,4,5,6]
dieSums = []
count = 0
while count <= 5 do
dieSums << die1[0] + die2[count]
count += 1
end
puts dieSums[5] #=> 7
As a side note: notice that you are over-complicating the problem (because you think in imperative terms, take a look at Functional programming). The sum of all possible values for two dice:
>> die = [1,2,3,4,5,6]
>> die.product(die).map { |v1, v2| v1 + v2 }
=> [2, 3, 4, 5, 6, 7, 3, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 9, 5, 6, 7, 8, 9, 10, 6, 7, 8, 9, 10, 11, 7, 8, 9, 10, 11, 12]
Call uniq at the end if you don't want repeated values.
Use repeated_combination(2) instead of product if you don't care about the order.
Note that die.product(die) = die.repeated_permutation(2))
Finding all the sums for N dice is almost as simple:
>> die.repeated_permutation(5).map { |values| values.inject(:+) }

How to create list of numbers and append its reverse to it efficiently in Ruby

Given a minimum integer and maximum integer, I want to create an array which counts from the minimum to the maximum by two, then back down (again by two, repeating the maximum number).
For example, if the minimum number is 1 and the maximum is 9, I want [1, 3, 5, 7, 9, 9, 7, 5, 3, 1].
I'm trying to be as concise as possible, which is why I'm using one-liners.
In Python, I would do this:
range(1, 10, 2) + range(9, 0, -2)
In Ruby, which I'm just beginning to learn, all I've come up with so far is:
(1..9).inject([]) { |r, num| num%2 == 1 ? r << num : r }.reverse.inject([]) { |r, num| r.unshift(num).push(num) }
Which works, but I know there must be a better way. What is it?
(1..9).step(2).to_a + (1..9).step(2).to_a.reverse
But shorter would be
Array.new(10) { |i| 2 * [i, 9-i].min + 1 }
if we're code golfing :)

Resources