Ruby from-to-step Sequence - ruby

def generator(from, to, step)
ary = [from]
nex = from += step
min = from += step
while from != to
if from < to
from += step
ary.push(nex)
nex += step
elsif from > to
from -= step
ary.push(min)
min -= step
else
return nil
end
end
return ary
end
can Someone help explain to me why this only returns up to the 'to'element minus 2
for example when
generator(10,20,1) it will return [10,11,12..18] instead of going all the way to 20

Change
nex = from += step
min = from += step
To
nex = from + step
min = from + step
Your from is already being incremented twice with the step because of that (so it loops less than intended).
If you want to write it in a one-liner you could do something like this using Numeric#step
2.3.0 > 10.step(20).to_a
#=> [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
2.3.0 > 20.step(10, -1).to_a
#=> [20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10]

Related

Ruby 100 doors returning 100 nil

I'm solving the '100 doors' problem from Rosetta Code in Ruby. Briefly,
there are 100 doors, all closed, designated 1 to 100
100 passes are made, designated 1 to 100
on the ith pass, every ith door is "toggled": opened if it's closed, closed if it's open
determine the state of each door after 100 passes have been completed.
Therefore, on the first pass all doors are opened. On the second pass even numbered doors are closed. On the third pass doors i for which i%3 == 0 are toggled, and so on.
Here is my attempt at solving the problem.
visit_number = 0
door_array = []
door_array = 100.times.map {"closed"}
until visit_number == 100 do
door_array = door_array.map.with_index { |door_status, door_index|
if (door_index + 1) % (visit_number + 1) == 0
if door_status == "closed"
door_status = "open"
elsif door_status == "open"
door_status = "closed"
end
end
}
visit_number += 1
end
print door_array
But it keeps printing me an array of 100 nil when I run it: Look at all this nil !
What am I doing wrong?
That's what your if clauses return. Just add a return value explicitly.
until visit_number == 100 do
door_array = door_array.map.with_index { |door_status, door_index|
if (door_index + 1) % (visit_number + 1) == 0
if door_status == "closed"
door_status = "open"
elsif door_status == "open"
door_status = "closed"
end
end
door_status
}
visit_number += 1
end
OR:
1.upto(10) {|i| door_array[i*i-1] = 'open'}
The problem is the outer if block doesn't explicitly return anything (thus returns nil implicitly) when the condition does not meet.
A quick fix:
visit_number = 0
door_array = []
door_array = 100.times.map {"closed"}
until visit_number == 100 do
door_array = door_array.map.with_index { |door_status, door_index|
if (door_index + 1) % (visit_number + 1) == 0
if door_status == "closed"
door_status = "open"
elsif door_status == "open"
door_status = "closed"
end
else #<------------- Here
door_status #<------------- And here
end
}
visit_number += 1
end
print door_array
Consider these approaches:
door_array.map { |door|
case door
when "open"
"closed"
when "closed"
"open"
end
}
or
rule = { "open" => "closed", "closed" => "open" }
door_array.map { |door| rule[door] }
or
door_array.map { |door| door == 'open' ? 'closed' : 'open' }
Code
require 'prime'
def even_nbr_divisors?(n)
return false if n==1
arr = Prime.prime_division(n).map { |v,exp| (0..exp).map { |i| v**i } }
arr.shift.product(*arr).map { |a| a.reduce(:*) }.size.even?
end
closed, open = (1..100).partition { |n| even_nbr_divisors?(n) }
closed #=> [ 2, 3, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22,
# 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 38, 39, 40,
# 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 57,
# 58, 59, 60, 61, 62, 63, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
# 75, 76, 77, 78, 79, 80, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
# 92, 93, 94, 95, 96, 97, 98, 99],
open #= [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
Explanation
All doors are initially closed. Consider the 24th door. It is toggled during the following passes:
pass 1: opened
pass 2: closed
pass 3: opened
pass 4: closed
pass 6: opened
pass 8: closed
pass 12: opened
pass 24: closed
Notice that the door is toggled once for each of 24's divisors. Therefore, if we had a method divisors(n) that returned an array of n's divisors, we could determine the number of toggles as follows:
nbr_toggles = divisors(24).size
#=> [1,2,3,4,6,8,12,24].size
#=> 8
Since the door is toggled an even number of times, we conclude that it will be in its original state (closed) after all the dust has settled. Similarly, for n = 9,
divisors(9).size
#=> [1,3,9].size
#=> 3
We therefore conclude door #9 will be open at the end, since 3 is odd.
divisors can be defined as follows.
def divisors(n)
arr = Prime.prime_division(n).map { |v,exp| (0..exp).map { |i| v**i } }
arr.first.product(*arr[1..-1]).map { |a| a.reduce(:*) }
end
For example,
divisors 24
#=> [1, 3, 2, 6, 4, 12, 8, 24]
divisors 9
#=> [1, 3, 9]
divisors 1800
#=> [1, 5, 25, 3, 15, 75, 9, 45, 225, 2, 10, 50, 6, 30, 150, 18, 90, 450,
# 4, 20, 100, 12, 60, 300, 36, 180, 900, 8, 40, 200, 24, 120, 600, 72,
# 360, 1800]
Since we only care if there are an odd or even number of divisors, we can instead write
def even_nbr_divisors?(n)
return false if n==1
arr = Prime.prime_division(n).map { |v,exp| (0..exp).map { |i| v**i } }
arr.shift.product(*arr).map { |a| a.reduce(:*) }.size.even?
end
For n = 24, the steps are as follows:
n = 24
a = Prime.prime_division(n)
#=> [[2, 3], [3, 1]]
arr = a.map { |v,exp| (0..exp).map { |i| v**i } }
#=> [[1, 2, 4, 8], [1, 3]]
b = arr.shift
#=> [1, 2, 4, 8]
arr
#=> [[1, 3]]
c = b.product(*arr)
#=> [[1, 1], [1, 3], [2, 1], [2, 3], [4, 1], [4, 3], [8, 1], [8, 3]]
d = c.map { |a| a.reduce(:*) }
#=> [1, 3, 2, 6, 4, 12, 8, 24]
e = d.size
#=> 8
e.even?
#=> true
Lastly,
(1..100).partition { |n| even_nbr_divisors?(n) }
returns the result shown above.

Reduce array of numbers (sequence)

Imagine having an array of numbers defined as: a = [18, 20, 21, 22, 23]. I want to modify it so that it would look like this: a = [18, (20..23)]. What is the most elegant solution for that one?
Here is a code minimally modified from doc: Enumerable#slice_before.
i = a[0]
a.slice_before do |e|
i, j = e, i
j + 1 != e
end
.flat_map{|es| es.length < 3 ? es : es.first..es.last}
# => [18, 20..23]
a = [18, 20, 21, 22, 23,13,14].sort!
prev = a[0]
p a.slice_before { |e|
prev, prev2 = e, prev
prev2 + 1 != e
}.flat_map{|i| next Range.new(i.first,i.last) if i.size !=1 ; i}
#=> [13..14, 18, 20..23]

How can I convert this array so that each element represents the cumulative value of the previous elements? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Cumulative array sum in Ruby
I have an array of integers like this
[20, 25, 40, 60]
How can I turn it into an array with each element representing the cumulative value of the elements before it, including itself?
[20, 45, 85, 145]
I'm using Rails 3.2.0 & ruby 1.9.3
s = 0
[20, 25, 40, 60].map{|e| s += e}
[20, 25, 40, 60].reduce([]) do |arr, v|
arr << (arr.last || 0) + v
end
Or an ugly one liner.
[20, 25, 40, 60].reduce([0]){ |a, v| a << a[-1] + v }[1..-1]
array = [20, 25, 40, 60]
(array.size - 1).times { |i| array[i + 1] += array[i] }
puts array
# => [20, 45, 85, 145]
arr = [20, 25, 40, 60]
first = []
sum = 0
arr.each do |e|
sum += e
first << sum
end
puts first
arr.each_with_index.map{|x, i| x + (i==0 ? 0 : arr[0..i-1].inject(:+))}
=> [20, 45, 85, 145]
Matlab:
B = cumsum(A)
Ruby:
class Array
def ruby_cumsum!
(1..size-1).each {|i| self[i] += self[i-1] }
self
end
end

Ruby find number of occurance within range

I have the following data where each row tells me a start and finish time of a process.
I would like to know from 12:20:00 to 14:00:00 with a step of 5 mins, I'd like to know how many processes running at each time instance. For example, there are 2 and 1 processes running at 12:30 and 12:35 respectively.
I'd like to implement this in Ruby 1.8 and what's the efficient Rubyiest way of doing this?
12:28:08, 12:33:29
12:28:20, 12:33:41
12:32:32, 12:32:44
12:36:56, 12:42:31
13:08:55, 13:09:08
14:09:00, 14:09:12
14:59:19, 15:04:37
15:41:40, 15:41:52
(Comments)
Ps: I have already got an array for the start time, sTime and end time, eTime. I want to do something like this:
(sTime..eTime).step($time_interval) do |cTime| # Current Time
cnt = 0
(0..(sessionstarttime.length-1)).each {|i| if cTime.between? (sessionstarttime[i], sessionendtime[i]); cnt += 1}
printf "%s, %d\n", cTime.strftime("%d/%m/%Y %H:%M:%S"), cnt
end
You can try this code (developed on 1.9 but should work on 1.8 as well):
a = %Q{
12:28:08, 12:33:29
12:28:20, 12:33:41
12:32:32, 12:32:44
12:36:56, 12:42:31
13:08:55, 13:09:08
14:09:00, 14:09:12
14:59:19, 15:04:37
15:41:40, 15:41:52
}
start = '12:20:00'
stop = '14:00:00'
require 'stringio'
def time_to_sec(time)
a = time.split(':').map(&:to_i)
a[0] * 3600 + a[1] * 60 + a[2]
end
def sec_to_time(sec)
h, n = sec.divmod 3600
m, s = n.divmod 60
"%02d:%02d:%02d" % [h, m, s]
end
rows = StringIO.new(a).read.delete(",").split("\n").reject{ |i| i.empty? }.map do |range|
range.split.map{ |time| time_to_sec(time) }
end
ranges = rows.map{ |i| i[0]..i[1] }
(time_to_sec(start)..time_to_sec(stop)).step(5*60) do |time|
cnt = ranges.count{|i| i.include? time}
puts "#{sec_to_time(time)}: #{cnt}"
end
Of course you don't need 'a' variable or StringIO if working with real files.
If you convert the values to a Time object (note I've assumed a date of 2000-01-01 for this example), you can do the following:
a= [
{ :s=> Time.utc(2000, 1, 1, 12, 28, 8), :e=> Time.utc(2000, 1, 1, 12, 33, 29) },
{ :s=> Time.utc(2000, 1, 1, 12, 28, 20), :e=> Time.utc(2000, 1, 1, 12, 33, 41) },
{ :s=> Time.utc(2000, 1, 1, 12, 32, 32), :e=> Time.utc(2000, 1, 1, 12, 32, 44) },
{ :s=> Time.utc(2000, 1, 1, 12, 36, 56), :e=> Time.utc(2000, 1, 1, 12, 42, 31) },
{ :s=> Time.utc(2000, 1, 1, 13, 8, 55), :e=> Time.utc(2000, 1, 1, 13, 9, 8) },
{ :s=> Time.utc(2000, 1, 1, 14, 9, 0), :e=> Time.utc(2000, 1, 1, 14, 9, 12) },
{ :s=> Time.utc(2000, 1, 1, 14, 59, 19), :e=> Time.utc(2000, 1, 1, 15, 4, 37) },
{ :s=> Time.utc(2000, 1, 1, 15, 41, 40), :e=> Time.utc(2000, 1, 1, 15, 41, 52) }
]
checkTime = Time.utc(2000, 1, 1, 12, 32, 40)
a.delete_if{|b| #b[:s] is start time, b[:e] is end time
(b[:s] > checkTime) || (b[:e] < checkTime)
}
Here are a couple of simple objects that model something that should calculate what you need. This gives you a start to an interface you can use to do more complex logic if you need it.
require 'time'
# Object Definitions
class ProcessTimelineEntry
def initialize(start_time, end_time)
#start_time = start_time
#end_time = end_time
end
def running_at?(time)
time >= #start_time && time < #end_time
end
end
class ProcessTimeline
def initialize()
#entries = []
end
def add_entry(start_time, end_time)
#entries << ProcessTimelineEntry.new(start_time, end_time)
end
def process_count_at(time)
#entries.count { |e| e.running_at?(time) }
end
end
# Example Usage
timeline = ProcessTimeline.new
DATA.readlines.each do |line|
start_time, end_time = line.split(', ')
timeline.add_entry(Time.parse(start_time), Time.parse(end_time))
end
puts timeline.process_count_at(Time.parse("12:30"))
puts timeline.process_count_at(Time.parse("12:35"))
__END__
12:28:08, 12:33:29
12:28:20, 12:33:41
12:32:32, 12:32:44
12:36:56, 12:42:31
13:08:55, 13:09:08
14:09:00, 14:09:12
14:59:19, 15:04:37
15:41:40, 15:41:52
Here is a solution which will scale better to large numbers of start-stop pairs or time steps than the other posted answers (given that you want to know the number of processes running during each time step, not just 1 or 2 selected time steps):
START = Time.utc(2000,1,1, 12,20,0).to_i
FINISH = Time.utc(2000,1,1, 14,0,0).to_i
STEP = 60*5 # 5 minutes
result = Array.new(((FINISH-START).to_f/STEP).ceil, 0)
processes = %Q{
12:28:08, 12:33:29
12:28:20, 12:33:41
12:32:32, 12:32:44
12:36:56, 12:42:31
13:08:55, 13:09:08
14:09:00, 14:09:12
14:59:19, 15:04:37
15:41:40, 15:41:52 }
processes.each_line do |times|
times =~ /(\d\d):(\d\d):(\d\d), (\d\d):(\d\d):(\d\d)/
st = Time.utc(2000,1,1, $1.to_i,$2.to_i,$3.to_i).to_i
fin = Time.utc(2000,1,1, $4.to_i,$5.to_i,$6.to_i).to_i
st = START if st < START
fin = END if fin > END
(st..fin).step(STEP) do |t|
result[(t-START)/STEP] += 1
end
end
The count of how many processes were running during each time step will be left in result. You can put an object wrapper around it if desired to provide a nice interface.

Ruby: After inserting arrays into a list, how can I retrieve them and process them as arrays?

Here's what I'm trying to do:
val1 = [26, 27, 24, 25, 29, 28]
val2 = [17, 20, 22, 21]
val3 = [36, 33, 31, 29]
val4 = [20, 18, 17, 22, 21, 23]
vals = {val1, val2, val3, val4}
sum = 0
count = 0
vals.each do |val|
for i in 0..val.size-1 do
#sum += val[i]
p val[i]
++count
end
end
puts sum
puts count
Initially I wanted to just get sum and count, but that wasn't working so I tried printing. I can see that the val[i] isn't working as I intended though. I tried doing this:
vals.each do |val|
aux = val.to_a
for i in 0..aux.size-1 do
p aux[i]
++count
end
end
But it had the same results. I'm still trying to learn the basics, so I really have no idea what to do now.
Come on guys this is Ruby!
val1 = [26, 27, 24, 25, 29, 28]
val2 = [17, 20, 22, 21]
val3 = [36, 33, 31, 29]
val4 = [20, 18, 17, 22, 21, 23]
vals = [val1, val2, val3, val4]
To get the sum...
vals.flatten.sum
=> 489
To get the count...
vals.flatten.count
=> 20
You could even return them both in a hash if you wanted...
vals.flatten.instance_eval { {:count => count, :sum => sum}}
=> {:count=>20, :sum=>489}
val1 = [26, 27, 24, 25, 29, 28]
val2 = [17, 20, 22, 21]
val3 = [36, 33, 31, 29]
val4 = [20, 18, 17, 22, 21, 23]
vals = [val1, val2, val3, val4]
sum = 0
count = 0
vals.each do |val|
for i in 0...val.size do
sum += val[i]
p val[i]
count += 1
end
end
puts sum
puts count
This works. {} is not a list, [] is actually a list. When you write {val1, val2, val3, val4} you have created a hash, associative array, with val1 and val3 as keys and val2 and val4 as values. val would be in [val1, val2] form, no wonder you can't sum that up.
BTW, you can use ...size instead of ..size-1 in arrays. But val.each will still be better.

Resources