Declaring an integer Range with step != 1 in Ruby - ruby

UPDATE 2: For posterity, this is how I've settled on doing it (thanks to Jorg's input):
100.step(2, -2) do |x|
# my code
end
(Obviously there are plenty of ways to do this; but it sounds like this is the most "Ruby" way to do it; and that's exactly what I was after.)
UPDATE: OK, so what I was looking for was step:
(2..100).step(2) do |x|
# my code
end
But it turns out that I wasn't 100% forthcoming in my original question. I actually want to iterate over this range backwards. To my surprise, a negative step isn't legal.
(100..2).step(-2) do |x|
# ArgumentError: step can't be negative
end
So: how do I do this backwards?
I am completely new to Ruby, so be gentle.
Say I want to iterate over the range of even numbers from 2 to 100; how would I do that?
Obviously I could do:
(2..100).each do |x|
if x % 2 == 0
# my code
end
end
But, obviously (again), that would be pretty stupid.
I know I could do something like:
i = 2
while i <= 100
# my code
i += 2
end
I believe I could also write my own custom class that provides its own each method (?). I am almost sure that would be overkill, though.
I'm interested in two things:
Is it possible to do this with some variation of the standard Range syntax (i.e., (x..y).each)?
Either way, what would be the most idiomatic "Ruby way" of accomplishing this (using a Range or otherwise)? Like I said, I'm new to the language; so any guidance you can offer on how to do things in a more typical Ruby style would be much appreciated.

You can't declare a Range with a "step". Ranges don't have steps, they simply have a beginning and an end.
You can certainly iterate over a Range in steps, for example like this:
(2..100).step(2).reverse_each(&method(:p))
But if all you want is to iterate, then what do you need the Range for in the first place? Why not just iterate?
100.step(2, -2, &method(:p))
This has the added benefit that unlike reverse_each it does not need to generate an intermediate array.

This question answers yours: about ruby range?
(2..100).step(2) do |x|
# your code
end

I had similar issue here are the various ways I found to do the same SIMPLE thing I used step in the end because it allowed for NEGATIVE and FRACTIONAL increments and I had no conditions, other than the bounds to look for
case loop_type
when FOR
# doen't appear to have a negative or larger than 1 step size!
for kg in 50..120 do
kg_to_stones_lbs(kg)
end
when STEP
120.step(70,-0.5){ |kg|
kg_to_stones_lbs(kg)
}
when UPTO
50.upto(120) { |kg|
kg_to_stones_lbs(kg)
}
when DOWNTO
120.downto(50){ |kg|
kg_to_stones_lbs(kg)
}
when RANGE
(50..120).reverse_each{ |kg|
kg_to_stones_lbs(kg)
}
when WHILE
kg = 120
while kg >= 50
kg_to_stones_lbs(kg)
kg -= 0.5
end
end
O/P:
92.0kg - 14st 7lbs
91.5kg - 14st 6lbs
91.0kg - 14st 5lbs
90.5kg - 14st 4lbs
90.0kg - 14st 2lbs
89.5kg - 14st 1lbs
89.0kg - 14st 0lbs
88.5kg - 13st 13lbs
88.0kg - 13st 12lbs

Related

Optimizing Array Memory Usage

I currently have a very large array of permutations, which is currently using a significant amount of RAM. This is the current code I have which SHOULD:
Count all but the occurrences where more than one '1' exists or three '2's exist in a row.
arr = [*1..3].repeated_permutation(30).to_a;
count = 0
arr.each do |x|
if not x.join('').include? '222' and x.count(1) < 2
count += 1
end
end
print count
So basically this results in a 24,360 element array, each of which have 30 elements.
I've tried to run it through Terminal but it literally ate through 14GB of RAM, and didn't move for 15 minutes, so I'm not sure whether the process froze while attempting to access more RAM or if it was still computing.
My question being: is there a faster way of doing this?
Thanks!
I am not sure what problem you try to solve. If your code is just an example for a more complex problem and you really need to check programatically every single permumation, then you might want to experiment with lazy:
[*1..3].repeated_permutation(30).lazy.each do ||
# your condition
end
Or you might want to make the nested iteratior very explicit:
[1,2,3].each do |x1|
[1,2,3].each do |x2|
[1,2,3].each do |x3|
# ...
[1,2,3].each do |x30|
permutation = [x1,x2,x3, ... , x30]
# your condition
end
end
end
end
end
But it feels wrong to me to solve this kind of problem with Ruby enumerables at all. Let's have a look at your strings:
111111111111111111111111111111
111111111111111111111111111112
111111111111111111111111111113
111111111111111111111111111121
111111111111111111111111111122
111111111111111111111111111123
111111111111111111111111111131
...
333333333333333333333333333323
333333333333333333333333333331
333333333333333333333333333332
333333333333333333333333333333
I suggest to just use enumerative combinatorics. Just look at the patterns and analyse (or count) how often your condition can be true. For example there are 28 indexes in your string at which a 222 substring could be place, only 27 for the 2222 substring... If you place a substring how likely is it that there is no 1 in the other parts of the string?
I think your problem is a mathematics problem, not a programming problem.
NB This is an incomplete answer, but I think the idea might give a push to the proper solution.
I can think of a following approach: let’s represent each permutation as a value in ternary number base, padded by zeroes:
1 = 000..00001
2 = 000..00002
3 = 000..00010
4 = 000..00011
5 = 000..00012
...
Now consider we restated the original task, treating zeroes as ones, ones as twos and twos as threes. So far so good.
The whole list of permutations would be represented by:
(1..3**30-1).map { |e| x = e.to_s(3).rjust(30, '0') }
Now we are to apply your conditions:
def do_calc permutation_count
(1..3**permutation_count-1).inject do |memo, e|
x = e.to_s(3).rjust(permutation_count, '0')
!x.include?('111') && x.count('0') < 2 ? memo + 1 : memo
end
Unfortunately, even for permutation_count == 20 it takes more than 5 minutes to calculate, so probably some additional steps are required. I will be thinking of further optimization. Currently I hope this will give you a hint to find the good approach yourself.

Ruby elegant alternative to ++ in nested loops?

Before anything, I have read all the answers of Why doesn't Ruby support i++ or i—? and understood why. Please note that this is not just another discussion topic about whether to have it or not.
What I'm really after is a more elegant solution for the situation that made me wonder and research about ++/-- in Ruby. I've looked up loops, each, each_with_index and things alike but I couldn't find a better solution for this specific situation.
Less talk, more code:
# Does the first request to Zendesk API, fetching *first page* of results
all_tickets = zd_client.tickets.incremental_export(1384974614)
# Initialises counter variable (please don't kill me for this, still learning! :D )
counter = 1
# Loops result pages
loop do
# Loops each ticket on the paged result
all_tickets.all do |ticket, page_number|
# For debug purposes only, I want to see an incremental by each ticket
p "#{counter} P#{page_number} #{ticket.id} - #{ticket.created_at} | #{ticket.subject}"
counter += 1
end
# Fetches next page, if any
all_tickets.next unless all_tickets.last_page?
# Breaks outer loop if last_page?
break if all_tickets.last_page?
end
For now, I need counter for debug purposes only - it's not a big deal at all - but my curiosity typed this question itself: is there a better (more beautiful, more elegant) solution for this? Having a whole line just for counter += 1 seems pretty dull. Just as an example, having "#{counter++}" when printing the string would be much simpler (for readability sake, at least).
I can't simply use .each's index because it's a nested loop, and it would reset at each page (outer loop).
Any thoughts?
BTW: This question has nothing to do with Zendesk API whatsoever. I've just used it to better illustrate my situation.
To me, counter += 1 is a fine way to express incrementing the counter.
You can start your counter at 0 and then get the effect you wanted by writing:
p "#{counter += 1} ..."
But I generally wouldn't recommend this because people do not expect side effects like changing a variable to happen inside string interpolation.
If you are looking for something more elegant, you should make an Enumerator that returns integers one at a time, each time you call next on the enumerator.
nums = Enumerator.new do |y|
c = 0
y << (c += 1) while true
end
nums.next # => 1
nums.next # => 2
nums.next # => 3
Instead of using Enumerator.new in the code above, you could just write:
nums = 1.upto(Float::INFINITY)
As mentioned by B Seven each_with_index will work, but you can keep the page_number, as long all_tickets is a container of tuples as it must be to be working right now.
all_tickets.each_with_index do |ticket, page_number, i|
#stuff
end
Where i is the index. If you have more than ticket and page_number inside each element of all_tickets you continue putting them, just remember that the index is the extra one and shall stay in the end.
Could be I oversimplified your example but you could calculate a counter from your inner and outer range like this.
all_tickets = *(1..10)
inner_limit = all_tickets.size
outer_limit = 5000
1.upto(outer_limit) do |outer_counter|
all_tickets.each_with_index do |ticket, inner_counter|
p [(outer_counter*inner_limit)+inner_counter, outer_counter, inner_counter, ticket]
end
# some conditional to break out, in your case the last_page? method
break if outer_counter > 3
end
all_tickets.each_with_index(1) do |ticket, i|
I'm not sure where page_number is coming from...
See Ruby Docs.

How do I convert a spreadsheet "letternamed" column coordinate to an integer?

In spreadsheets I have cells named like "F14", "BE5" or "ALL1". I have the first part, the column coordinate, in a variable and I want to convert it to a 0-based integer column index.
How do I do it, preferably in an elegant way, in Ruby?
I can do it using a brute-force method: I can imagine loopping through all letters, converting them to ASCII and adding to a result, but I feel there should be something more elegant/straightforward.
Edit: Example: To simplify I do only speak about the column coordinate (letters). Therefore in the first case (F14) I have "F" as the input and I expect the result to be 5. In the second case I have "BE" as input and I expect getting 56, for "ALL" I want to get 999.
Not sure if this is any clearer than the code you already have, but it does have the advantage of handling an arbitrary number of letters:
class String
def upcase_letters
self.upcase.split(//)
end
end
module Enumerable
def reverse_with_index
self.map.with_index.to_a.reverse
end
def sum
self.reduce(0, :+)
end
end
def indexFromColumnName(column_str)
start = 'A'.ord - 1
column_str.upcase_letters.map do |c|
c.ord - start
end.reverse_with_index.map do |value, digit_position|
value * (26 ** digit_position)
end.sum - 1
end
I've added some methods to String and Enumerable because I thought it made the code more readable, but you could inline these or define them elsewhere if you don't like that sort of thing.
We can use modulo and the length of the input. The last character will
be used to calculate the exact "position", and the remainders to count
how many "laps" we did in the alphabet, e.g.
def column_to_integer(column_name)
letters = /[A-Z]+/.match(column_name).to_s.split("")
laps = (letters.length - 1) * 26
position = ((letters.last.ord - 'A'.ord) % 26)
laps + position
end
Using decimal representation (ord) and the math tricks seems a neat
solution at first, but it has some pain points regarding the
implementation. We have magic numbers, 26, and constants 'A'.ord all
over.
One solution is to give our code better knowlegde about our domain, i.e.
the alphabet. In that case, we can switch the modulo with the position of
the last character in the alphabet (because it's already sorted in a zero-based array), e.g.
ALPHABET = ('A'..'Z').to_a
def column_to_integer(column_name)
letters = /[A-Z]+/.match(column_name).to_s.split("")
laps = (letters.length - 1) * ALPHABET.size
position = ALPHABET.index(letters.last)
laps + position
end
The final result:
> column_to_integer('F5')
=> 5
> column_to_integer('AK14')
=> 36
HTH. Best!
I have found particularly neat way to do this conversion:
def index_from_column_name(colname)
s=colname.size
(colname.to_i(36)-(36**s-1).div(3.5)).to_s(36).to_i(26)+(26**s-1)/25-1
end
Explanation why it works
(warning spoiler ;) ahead). Basically we are doing this
(colname.to_i(36)-('A'*colname.size).to_i(36)).to_s(36).to_i(26)+('1'*colname.size).to_i(26)-1
which in plain English means, that we are interpreting colname as 26-base number. Before we can do it we need to interpret all A's as 1, B's as 2 etc. If only this is needed than it would be even simpler, namely
(colname.to_i(36) - '9'*colname.size).to_i(36)).to_s(36).to_i(26)-1
unfortunately there are Z characters present which would need to be interpreted as 10(base 26) so we need a little trick. We shift every digit 1 more then needed and than add it at the end (to every digit in original colname)
`

Unexpected $end after while loop and nested if

I have this program that I am working on that is supposed to find the sum of the first 1000 prime numbers. Currently all I am concerned with is making sure that the program is finding the first 1000 prime numbers, I will add the functionality for adding them later. Here is what I have:
#!/usr/bin/ruby
def prime(num)
is_prime = true
for i in 2..Math.sqrt(num)
if (num % i) == 0
is_prime = false
else
is_prime = true
end
end
return is_prime
end
i = 2
number_of_primes = 0
while number_of_primes < 1000
prime = prime(i)
if prime == true
number_of_primes++
end
i++
end
When i try to run the program I get the following feedback:
sumOfPrimes.rb:32: syntax error, unexpected keyword_end
sumOfPrimes.rb:34: syntax error, unexpected keyword_end
what gives? Any direction is appreciated.
Ruby doesn't have ++ operator, you need to do += 1
number_of_primes += 1
Unasked for, but a few pieces of advice if you're interested:
One of the cool things about Ruby is that question marks are legal in method names. As such you'll often find that 'predicate' methods (methods that test something and return true or false) end with a question mark, like this: odd?. Your prime method is a perfect candidate for this, so we can rename it prime?.
You use a local variable, is_prime, to hold whether you have found a factor of the number you're testing yet - this is the kind of thing you'd expect to do in an imperative language such as java or C - but Ruby has all sorts of cool features from functional programming that you will gain great power and expressiveness by learning. If you haven't come across them before, you may need to google what a block is and how the syntax works, but for this purpose you can just think of it as a way to get some code run on every item of a collection. It can be used with a variety of cool methods, and one of them is perfectly suited to your purpose: none?, which returns true if no items in the collection it is called on, when passed to the code block you give, return true. So your prime? method can be rewritten like this:
def prime? num
(2..Math.sqrt(num)).none? { |x| num % x == 0 }
end
Apart from being shorter, the advantage of not needing to use local variables like is_prime is that you give yourself fewer opportunities to introduce bugs - if for example you think the contents of is_prime is one thing but it's actually another. It's also, if you look carefully, a lot closer to the actual mathematical definition of a prime number. So by cutting out the unnecessary code you can get closer to exposing the 'meaning' of what you're writing.
As far as getting the first 1000 primes goes, infinite streams are a really cool way to do this but are probably a bit complex to explain here - definitely google if you're interested as they really are amazing! But just out of interest, here's a simple way you could do it using just recursion and no local variables (remember local variables are the devil!):
def first_n_primes(i = 2, primes = [], n)
if primes.count == n then primes
elsif prime? i then first_n_primes(i + 1, primes + [i], n)
else first_n_primes(i + 1, primes, n)
end
end
And as far as summing them up goes all I'll say is have a search for a ruby method called inject - also called reduce. It might be a bit brain-bending at first if you haven't come across the concept before but it's well worth learning! Very cool and very powerful.
Have fun!

Code folding on consecutive collect/select/reject/each

I play around with arrays and hashes quite a lot in ruby and end up with some code that looks like this:
sum = two_dimensional_array.select{|i|
i.collect{|j|
j.to_i
}.sum > 5
}.collect{|i|
i.collect{|j|
j ** 2
}.average
}.sum
(Let's all pretend that the above code sample makes sense now...)
The problem is that even though TextMate (my editor of choice) picks up simple {...} or do...end blocks quite easily, it can't figure out (which is understandable since even I can't find a "correct" way to fold the above) where the above blocks start and end to fold them.
How would you fold the above code sample?
PS: considering that it could have 2 levels of folding, I only care about the outer consecutive ones (the blocks with the i)
To be honest, something that convoluted is probably confusing TextMate as much as anyone else who has to maintain it, and that includes you in the future.
Whenever you see something that rolls up into a single value, it's a good case for using Enumerable#inject.
sum = two_dimensional_array.inject(0) do |sum, row|
# Convert row to Fixnum equivalent
row_i = row.collect { |i| i.to_i }
if (row_i.sum > 5)
sum += row_i.collect { |i| i ** 2 }.average
end
sum # Carry through to next inject call
end
What's odd in your example is you're using select to return the full array, allegedly converted using to_i, but in fact Enumerable#select does no such thing, and instead rejects any for which the function returns nil. I'm presuming that's none of your values.
Also depending on how your .average method is implemented, you may want to seed the inject call with 0.0 instead of 0 to use a floating-point value.

Resources