Calculate missing values in an array from adjacent values - ruby

Given an array
[50,30,0,0,10,0,30,60,0]
I need to replace the zeroes with calculated values to create a 'curve', so for example, between 10 and 30, the zero could be replaced with 20.
I keep thinking there must be a cool ruby way of doing this, but I cant find one. Can anyone help? The solution needs to take into account multiple adjacent zeroes, and zeroes at the start and end of the range.
Anyone any ideas?

The term you seem to be unaware of is interpolation. The Wikipedia article is a good place to start - exactly what algoithm is best suited to you depends on the exact context of your problem so we can't give you the one true answer here.

a =[50,30,0,0,10,0,30,60,0]
a.each_index{|i| a[i] = a[i-1] - ((a[i-2] - a[i-1])/2).to_i if a[i] == 0 && i > 1 }
puts a.inspect # [50, 30, 20, 15, 10, 8, 30, 60, 75]
I can't work out why the last number might be 80 in your spec however? Plus it doesn't work for the first two items in the array.

If there could not be consecutive zeroes, this unintelligible one-liner would do the trick (list is the given list of numbers):
[0, *list, 0].each_cons(3).map { |p, x, n| x == 0 ? (p + n)/2 : x }
Ruby 1.9 only, I think.

def find_consecutive_values( array, value=nil )
raise "Need a value or block to find" unless value || block_given?
start = last = nil
ranges = []
indices = array.each_with_index do |o,i|
if ((block_given? && yield(o)) || o==value)
start = i unless start
last = i
else
ranges << (start..last) if start && last
start = last = nil
end
end
ranges << (start..last) if start && last
ranges
end
def interpolate_zeros( array, round=false )
result = array.dup
find_consecutive_values( array, 0 ).each do |range|
next unless range.first>0 && range.last<(array.length-1)
before = result[range.first - 1]
after = result[range.last + 1]
diff = after - before
size = (range.last - range.first + 2).to_f
range.each_with_index do |i,idx|
value = before + diff * (idx+1)/size
value = value.round if round
result[i] = value
end
end
result
end
p interpolate_zeros( [0,50,30,0,0,10,0,30,60,0], true )
#=> [0, 50, 30, 23, 17, 10, 20, 30, 60, 0]

Just stumbled across this question. There is a ruby gem "interpolator", which just does what you want and probably tons more:
http://interpolator.rubyforge.org.
Here is a short introduction:
http://fabianosoriani.wordpress.com/2010/02/23/ruby-interpolation-with-gem-interpolator/

Related

Array Ilteration Ruby

A problem asks to print all numbers from an array that are greater than 100. When I run this:
array = [3, 123, 433, -77, 56, 200, 99, 101, 6]
index = 0
9.times do
if array[index] > 100 == 0
p array[index]
end
index = index + 1
end
the number 9 is printed. I put in the proper conditional if the number was greater than 100 to get printer. Can anyone help?
Just use
if array[index] > 100
# print
end
9 is the evaluation of your program, it's not a 'print', it's the result of 9.times
Your program doesn't print any of the array values because of that condition
if array[index] > 100 == 0
it should be just
if array[index] > 100
don't know why you add that == 0
array[index] > 100 is evaluted before so all the time you always obtain true == 0 or false == 0, and these are never true. So no prints in your code
about that 9 that come up it's what Aleksei says
The problem's actually really easy to solve if you know the right tools to use:
array = [3,123,433,-77,56,200,99,101,6]
array.select { |n| n > 100 }.each do |n|
puts n
end
Where select can help narrow down lists of numbers. Ruby's Array class has an unusually large number of methods like this that can quickly and easily do a variety of things related to filtering and mapping.
The 9.times part in your code was decoupled from the actual length of the array, something that leads to a whole lot of bugs if you add/remove entries and these two fall out of sync.
Use array iterators whenever possible, like:
array = [3,123,433,-77,56,200,99,101,6]
array.each do |n|
if (n > 100)
puts n
end
end
You have written 9.times which is your array size, which indicates you want to run it for all array elements. So use each block on array.
array.each { |x| puts x if x > 100 }
Try to understand why there is no role of index of any array element in above.
Select returns its own array. So we can just print the return value.
puts array.select{|x| x > 99}

Ruby quantify a range

I have a Ruby array that defines a set of integer thresholds
thresholds = [under_threshold_1, under_threshold_2, ..., under_threshold_n, over_threshold]
I want to map any integer to a value corresponding to the threshold number. Basically
if threshold_a < number < threshold_b
return threshold_a
end
Is there a cool way to do that in Ruby ? I Need to handle the "edge" cases < threshold_1 and > threshold_over. I could only come up with a (ugly but working) set of if statements or looping on the array.
I am actually free to modelise this how I want (I can change the array to something else if more convenient)
I was thinking there is maybe a cool way to splat the thresholds in a case/when clause
case number
when 0..threshold_1 then 0
when threshold_i..threshold_i+1 then i
else n
end
# example
thresholds = [ 4, 8, 10 ,12 ]
quantify(1) = 0
quantify(4) = 1
quantify(11) = 3
quantify(50) = 4
How about this?
thresholds = [ 4, 8, 10, 12 ]
def which_threshold(thresholds, n)
thresholds.find_index {|t| n < t } || thresholds.size
end
p which_threshold(thresholds, 1) # => 0
p which_threshold(thresholds, 4) # => 1
p which_threshold(thresholds, 11) # => 3
p which_threshold(thresholds, 50) # => 4
I think this is what you want:
Thresholds = [4, 8, 10, 12]
def quantify(n)
Thresholds.count { |t| n >= t }
end
This quantification of n you want happens to be the number of thresholds that n is greater than or equal to, and it's easy to compute that using Enumerable#count.

Maximum and minimum value in an Array

I wrote a Ruby code to get max and min values from an array. The code prints the max value (8) correct but it's not printing the minimum value (2). Please let me know what went wrong in my code.
class MaxMinArray
def MaxMinMethod()
array = [4,2,8,3,5]
maxNo = array[0]
minNo = array[0]
arrayLength = array.length
for i in 1..arrayLength
if array[i].to_i > maxNo
maxNo = array[i]
end
if array[i].to_i < minNo
minNo = array[i]
end
end
puts "Maximum no. in the given array: " + maxNo.to_s
puts "Minimum no. in the given array: " + minNo.to_s
end
end
MaxiMinArrayObj = MaxMinArray.new
MaxiMinArrayObj.MaxMinMethod()
It is the combination of two things.
First, you iterated over for i in 1..arrayLength, which iterates past the last element in array. After the last element, array[i] is nil.
Second, you have the condition if array[i].to_i < minNo, which can be satisfied even if array[i] is not a number.
Because of that, the nil returned by array[i] after the last element satisfies the condition due to nil.to_i being 0, and that nil is assigned to minNo.
I realize you're trying to learn how to code, but, as you do so, it's also important to learn to take advantage of pre-existing solutions. Reinventing wheels will waste your time debugging code.
I'd write the code like:
def max_min(ary)
[ary.max, ary.min]
end
max_min([1,2,4]) # => [4, 1]
But, then again, Ruby already has a good minmax method:
[1,2,4].minmax # => [1, 4]
so use it and focus your energy on more interesting things.
If you have to see the values in the opposite order, use:
[1,2,4].minmax.reverse # => [4, 1]
A more verbose/old-school way of doing it is:
FIXNUM_MAX = (2 ** (0.size * 8 - 2) - 1)
FIXNUM_MIN = -(2 ** (0.size * 8 - 2))
def max_min(ary)
return [nil, nil] if ary.empty?
minval = FIXNUM_MAX
maxval = FIXNUM_MIN
ary.each do |i|
minval = i if i < minval
maxval = i if i > maxval
end
[maxval, minval]
end
max_min([1,2,4]) # => [4, 1]
[1,2,4].minmax.reverse # => [4, 1]
That simply loops over the array, checks each value to see if it's either smaller or larger than the last minimum or maximum value, and, if so, remembers it. Once the array is exhausted the values are returned. It's a lot more concise because using each removes a lot of the hassle of trying to walk the array using index values. We almost never use for in Ruby, especially to walk through an array.
(Technically Ruby can hold values well beyond 4611686018427387903 and -4611686018427387904, which are what FIXNUM_MAX and FIXNUM_MIN are, but those suffice for most things we want to do.)
It's not a good practice to print inside methods as long as you might want to use the results for something else.
Also Ruby comes with all sorts of magic methods to get the maximum and minimum of an array:
results = [5, 23, 43, 2, 3, 0].minmax
puts "Maximum no. in the given array: " + results[1]
puts "Minimum no. in the given array: " + results[0]
You should iterate from 1 to arrayLength - 1 (it's an index of the last element). You can use three dots for this:
for i in 1...arrayLength
If I were not allowed to used Ruby's minmax method, than I would do it probably like this:
array = [4,2,8,3,5]
min, max = nil, nil
array.each do |element|
min = element if min.nil? || element < min
max = element if max.nil? || max < element
end
puts [min, max]
# => [2, 8]
I used this expression for the min and max within ruby, it's a stretch but it works
class RubyMinMax
def self.min_function(array=[])
puts "my array is the following #{array}"
puts "the length of the array is #{array.length}"
it = 0
while array.length > 1
array.fetch(it).to_i > array.fetch(it-1).to_i ? array.delete_at(it) : array.delete_at(it-1)
it = array.length-1
end
print array[0]
end
def self.max_function(array=[])
puts "my array is the following #{array}"
puts "the length of the array is #{array.length}"
it = 0
while array.length > 1
array.fetch(it).to_i < array.fetch(it-1).to_i ? array.delete_at(it) : array.delete_at(it-1)
it = array.length-1
end
print array[0]
end
end
RubyMinMax.min_function([18, 19, 17])
RubyMinMax.max_function([18, 19, 17])
In the simplest way you can use max and min method of array.
:001 > [1,4,1,3,4,5].max
=> 5
:002 > [1,4,1,3,4,5].min
=> 1
And if your array may contain nil the first compact it the use min max
For example
:003 > [1,4,1,3,4,5,nil].compact
=> [1, 4, 1, 3, 4, 5]
:004 > [1,4,1,3,4,5].max
=> 5
:005 > [1,4,1,3,4,5].min
=> 1

Ruby Enumeration: Taken first n where block returns true

I want to take the first "n" entries which pass the block
a = 1..100_000_000 # Basically a long array
# This iterates over the whole array -- no good
b = a.select{|x| x.expensive_operation?}.take(n)
I want to short circuit the iteration once i've got n entries where 'expensive' condition is true.
What do you suggest? take_while and keep count of n?
# This is the code i have; which i think can be written better, but how?
a = 1..100_000_000 # Basically a long array
n = 20
i = 0
b = a.take_while do |x|
((i < n) && (x.expensive_operation?)).tap do |r|
i += 1
end
end
Ruby 2.0 implements lazy enumerables, for older versions use the gem enumerable-lazy:
require 'enumerable/lazy'
(1..Float::INFINITY).lazy.select(&:even?).take(5).to_a
#=> [2, 4, 6, 8, 10]
It should work with a simple for loop and a break :
a = 1..100_000_000 # Basically a long array
n = 20
selected = []
for x in a
selected << x if x.expensive_operation?
break if select.length == n
end

How do I value from an array that returns objects at the beginning more often?

Given an array like [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], I want to get a random value that takes into consideration the position.
I want the likelihood of 1 popping up to be way bigger than 10.
Is something like this possible?
For the sake of simplicity let's assume an array arr = [x, y, z] from which we will be sampling values. We'd like to see following relative frequencies of x, y and z:
frequencies = [5, 2, 1]
Preprocess these frequencies to calculate margins for our subsequent dice roll:
thresholds = frequencies.clone
1.upto(frequencies.count - 1).each { |i| thresholds[i] += thresholds[i - 1] }
Let's sum them up.
max = frequencies.reduce :+
Now choose a random number
roll = 1 + rand max
index = thresholds.find_index { |x| roll <= x }
Return arr[index] as a result. To sum up:
def sample arr, frequencies
# assert arr.count == frequencies.count
thresholds = frequencies.clone
1.upto(frequencies.count - 1).each { |i| thresholds[i] += thresholds[i - 1] }
max = frequencies.reduce :+
roll = 1 + rand(max)
index = thresholds.find_index { |x| roll <= x }
arr[index]
end
Let's see how it works.
data = 80_000.times.map { sample [:x, :y, :z], [5, 2, 1] }
A histogram for data shows that sample works as we've intended.
def coin_toss( arr )
arr.detect{ rand(2) == 0 } || arr.last
end
a = (1..10).to_a
10.times{ print coin_toss( a ), ' ' } #=> 1 1 1 9 1 5 4 1 1 3
This takes the first element of the array, flips a coin, returns the element and stops if the coinflip is 'tails'; the same with the next element otherwise. If it is 'heads' all the way, return the last element.
A simple way to implement this with an logarithmic probabilistic of being selected is to simulate coin flips. Generate a random integer 0 and 1, the index to that array to choose is the number of consecutive 1s you get. With this method, the chance of selecting 2 is 1/2 as likely as 1, 3 is 1/4th as likely, etc. You can vary the probability slightly say by generating random numbers between 0 and 5 and count the number of consecutive rounds above 1, which makes each number in the array 4/5th as likely to appear as the one before.
A better and more general way to solve this problem is to use the alias method. See the answer to this question for more information:
Data structure for loaded dice?

Resources