I know that in ruby we can use a while loop, but I want to know if I can create a custom one so I can make something like this:
custom_while i < 5 do
puts i
i += 1
end
I currently have this code:
def custom_while(condition)
loop do
break if not condition
yield
end
end
i = 0
custom_while i < 5 do
puts i
i += 1
end
However, when condition is evaluated, it always get true (because it considers the first evaluation of i < 5 = true only.
Any help will be appreciated!
Note: This is for educational purposes only.
You almost had it. So, your problem is that the condition is only evaluated once? Well, what construct do we know that we can evaluate as often as we want? That's right: functions! So, let's make condition a function (or a Proc in Ruby lingo):
def custom_while(condition)
loop do
break unless condition.()
yield
end
end
i = 0
custom_while -> { i < 5 } do
puts i
i += 1
end
# 0
# 1
# 2
# 3
# 4
This is unfortunately not as nice looking as in other languages. Ruby's syntax and semantics are aggressively optimized for methods that take exactly 1 "function" as an argument. Ruby has a special syntactically and semantically light-weight construct for that, namely blocks. As soon as you have more than one, though, you're out of luck.
Compare this with languages that have proper block literals, like Smalltalk, for example. In Smalltalk, you could write a method while:do:, and call it like this:
i := 0.
while: [i < 5] do: [Transcript write: i. i := i + 1].
In fact, in Smalltalk, the syntax for blocks is so lightweight that there are no control structures at all in the language. if/then/else is simply an instance method of Boolean, for example:
i % 2 == 0 ifTrue: [Transcript write: "even"] ifFalse: [Transcript write: "odd"].
And while is actually an instance method of Block, so in reality, your example would look like this:
i := 0.
[i < 5] whileTrue: [Transcript write: i. i := i + 1]
Note: I make no guarantees for the Smalltalk code, I didn't test it.
The problem is, the condition is being evaluated before it's passed in, so it will never change.
Make the condition a function that you evaluate inside the loop, or use a macro to make it cleaner.
Related
I was wondering why loop is a Kernel method rather than a keyword like while and until. There are cases where I want to do unconditional loop, but since loop, being a method, is slower than while true, I chose to do the latter when performance is important. But writing true here looks ugly, and is not Rubish; loop looks better. Here is a dilemma.
My guess is that it is because there is a usage of loop that does not take a block and returns an enumerator. But to me, it looks that an unconditional loop can easily be created on the spot, and does not make sense to create such an instance of Enumerator and later use it. I cannot think of a use case.
Is my guess regarding my wonder correct? If not, why is loop a method rather than a keyword?
What is the use case for an enumerator created by loop without a block?
Only Ruby's developers can answer your first question, but your guess seems reasonable. As to your second question, sure there are use cases. The whole point of Enumerables is that you can pass them around, which, as you know, you can't do with a while or for structure.
As a trivial example, here's a Fibonacci sequence method that takes an Enumerable as an argument:
def fib(enum)
a, b = nil, nil
enum.each do
a, b = b || 0, a ? a + b : 1
puts a
end
puts "DONE"
end
Now suppose you want to print out the first seven Fibonacci numbers. You can use any Enumerable that yields seven times, like the one returned by 7.times:
fib 7.times
# => 0
# 1
# 1
# 2
# 3
# 5
# 8
# DONE
But what if you want to print out Fibonacci numbers forever? Well, just pass it the Enumerable returned by loop:
fib loop
# => 0
# 1
# ...
# (Never stops)
Like I said, this is a silly example that clearly is a terrible way to generate Fibonacci numbers, but hopefully it helps you understand that there are times—albeit perhaps rarely—when it's useful to have an Enumerable that never ends, and why loop is a nice convenience for those cases.
[1,2,3,4,5,6,7].delete_if{|i| i < 4 }
For example, in the above, why do you need to put |i| before i < 4?
I'm new to Ruby programming and the purpose of this element escapes me.
This is very basic Ruby syntax for a block. A block can sometimes take parameters which are given between the bars |. In your case:
[1,2,3,4,5,6,7].delete_if { |i| i < 4 }
The delete_if method for the type Array accepts a block as a parameter. When the bock is given, the block accepts the array element as a parameter. So it iterates i over each value within the array in this case. More specifically, an element will be deleted from the array if that element is < 4. The result will be:
[4,5,6,7]
You'll often see documentation for methods for Ruby types which say, for example:
delete_if { |item| block } -> Array
Which means that the method accepts a block with a parameter, the block being some code that uses the parameter, and the output being another array. The method's description explains more detail in the documentation (e.g., Ruby Array).
I recommend reading some Ruby getting started information online or a good introductory book which will explain this in more detail.
You have to put i there for the same reason you would put i in the first line here:
def plus_one(i)
return i + 1
end
You have to name your method argument, which you later use as a local variable in the method.
Ruby blocks are similar to methods, they can also receive arguments, and syntax for declaring them is slightly different: enclosing them in | |.
I've redone my answer, even though the OP's question has already been answered, because I thought of a new way to explain this that may help future SO users with the same question.
From high school algebra, you should remember functions like this: f(x) = x + 1.
Imagine putting curly braces around the x + 1: f(x) = { x + 1 }
Then move the (x) to inside the curly braces: f = {(x) x + 1 }
And then get rid of the name f: {(x) x + 1 }. This makes it an "anonymous function," i.e. a "lambda."
Here's the problem: The braces could contain arbitrary statements, which may themselves use parentheses: (x + 1) * 4. So how would Ruby know that the (x) is supposed to be an argument to the function, and not an expression to execute? Some other syntax had to be used. Hence the vertical bars: |x|. (At least I assume that was the thought process).
So {|i| i > 4 } is just like f(i) = i > 4, except that it has no name and is not defined in advance, so the parameter has to be defined "inside" the function itself, rather than being outside attached to the name.
Array#delete_if expects such a function (called a "block" when it's used like this) and knows what to do with it. It passes each member of the array [1,2,3,4,5,6,7] into the block as the argument i to see whether i > 4 is true for that member. It's equivalent to doing something like this:
def greater_than_four(x)
x > 4
end
arr = [1,2,3,4,5,6,7]
arr.each do |el|
arr.delete(el) if greater_than_four(el)
end
You could avoid defining the greater_than_four method in advance by defining a lambda on the fly like this:
arr = [1,2,3,4,5,6,7]
arr.each do |el|
arr.delete(el) if lambda{|i| i > 4}.call(el)
end
But since Array#delete_if already expects a block, and already knows to call it on each element, you can save yourself a whole lot of code:
[1,2,3,4,5,6,7].delete_if{|i| i < 4 }
The parameter which you are passing to the delete_if method is a block and the thing inside the parameter you pass to the block.
Think of the block as a method of sorts. The delete_if method iterates over the block and passes the current item as the parameter i to the block. If the condition evaluates to true then that element gets deleted.
The challenge is to find the smallest integer foo for which:
foo % 1..20 == 0
My current attempt is brute force
until foo % 1.upto(20) == 0 do
foo++
end
This outputs the error unexpected keyword end. But if I don't put the end keyword into irb the code never runs, because the block isn't closed.
I made an empty test case to see where my error lays
until foo % 1.upto(20) == 0 do
end
This throws a new error: enumerator can't be coerced to a fixnum. I imagine this means you can't directly perform modulus upon a range and expect a neat boolean result for the whole range. But I don't know where to go from here.
My first attempts forewent brute force in favor of an attempt at something more efficient/elegant/to-the-point and were as follows:
foo = 1
1.upto(20) {|bar| foo *= bar unless foo % i == 0}
gave the wrong answer. I don't understand why, but I'm also interested in why
foo = 1
20.downto(1) {|bar| foo *= bar unless foo % i == 0}
outputs a different answer.
EDIT: I would have used for loops (I got my feet wet with programming in ActionScript) but they do not work how I expect in ruby.
Your first solution is wrong because 1.upto(20) is an enumerator, that is, essentially an iterator over the values 1 to 20, and it cannot be used as a number for modulo or comparison to another number, since it itself isn't a number.
You really need two "loops" here:
foo = 1
foo += 1 until (1..20).all? { |i| foo % i == 0 }
the first loop is the until, and then the all? is another loop of sorts, in that it ensures that the block ({ |i| foo % i == 0 }) is true for each element in the range it is called on ((1..20)). Note that I'm using the one-line "backwards" syntax (which also works for if, unless, while, …)—the above is equivalent to:
foo = 1
until (1..20).all? { |i| foo % i == 0 } do
foo += 1
end
# foo => 232792560
Also, this is incredibly inefficient, Project Euler often involves a bit more math than programming, and a non-brute-force solution will likely involve more math but be far faster.
Try this:
until 1.upto(20).reject{|i| foo % i == 0 }.empty? do
foo += 1
end
I know it's not directly the OP question, but this is way easier to achieve with just:
puts (1..20).reduce(:lcm)
It's so simple that it seems like isn't fair to solve it this way, but that's precisely why Ruby is my language of choice for Project Euler.
See also this question
If this were me, I'd define a function to test the condition:
def mod_test(num)
test = (1..20).map {|i| num % i == 0}
test.all? # all are true
end
and then a loop to try different values:
foo = 20
until mod_test(foo) do
foo += 20
end
(Thanks to Dylan for the += 20 speedup.)
I'm sure that there's a clever way to use the knowledge of foo % 10 == 0 to also imply that foo % 5 == 0 and foo % 2 == 0, and perform only tests on prime numbers between 1 and 20, and probably even use that information to construct the number directly -- but my code ran quickly enough.
Within a method, I am using i and j as temporary variables while calculating other variables. What is an idiomatic way of getting rid of i and j once they are no longer needed? Should I use blocks for this purpose?
i = positions.first
while nucleotide_at_position(i-1) == nucleotide_at_position(i)
raise "Assumption violated" if i == 1
i -= 1
end
first_nucleotide_position = i
j = positions.last
while nucleotide_at_position(j+1) == nucleotide_at_position(j)
raise "Assumption violated" if j == sequence.length
j += 1
end
last_nucleotide_position = j
Background: I'd like to get rid of i and j once they are no longer needed so that they aren't used by any other code in the method. Gives my code less opportunity to be wrong. I don't know the name of the concept - is it "encapsulation"? The closest concepts I can think of are (warning: links to TV Tropes - do not visit while working) Chekhov'sGun or YouHaveOutlivedYourUsefulness.
Another alternative would be to put the code into their own methods, but that may detract from readability.
What makes you think splitting the code up into multiple methods will hurt the readability? In my experience, splitting even small or medium sized pieces of code into multiple methods can greatly improve readability.
Ruby (like JS) doesn't create a new scope for each block by default (as C++, etc. do). However, in Ruby 1.9, you can try:
last_nucleotide_position = nil
proc { |;i, j|
i = positions.first
while nucleotide_at_position(i-1) == nucleotide_at_position(i)
raise "Assumption violated" if i == 1
i -= 1
end
first_nucleotide_position = i
j = positions.last
while nucleotide_at_position(j+1) == nucleotide_at_position(j)
raise "Assumption violated" if j == sequence.length
j += 1
end
last_nucleotide_position = j
}.call()
See How to make block local variables the default in ruby 1.9?. Any variables that you want to be used outside the block should be defined before-hand (like last_nucleotide_position).
FM is right that a separate method may be more readable.
I think the term you are looking for is variable scope -- in other words, you are looking for ways to confine the scope of i and j. But you don't need to worry about that. The problem at hand calls for creating separate methods -- regardless of scope considerations.
This will improve readability, because it will allow the reader to grok the code starting at the high level and then boring in deeper only as needed. It will also improve testability because your small methods will do exactly one thing.
def calc_first_nucleotide_position(po)
i = po.first
while nucleotide_at_position(i-1) == nucleotide_at_position(i)
raise "Assumption violated" if i == 1
i -= 1
end
i
end
# etc...
first_nucleotide_position = calc_first_nucleotide_position(positions)
last_nucleotide_position = calc_last_nucleotide_position(positions)
# etc...
You are looking for the Ruby equivalent of Lisp's let special operator. Ruby does not support it out of the box but you can hack it in very easily, and the resulting syntax is like this:
x = 10
scope { |x|
x = 30
}
puts x #=> 10
see: http://banisterfiend.wordpress.com/2010/01/07/controlling-object-scope-in-ruby-1-9/
If all you want is to keep new variables from spilling out into the rest of your program, you can wrap your code in a block using 1.times. Any new variables you create inside the block will be destroyed when you close the block. Just keep in mind that any changes you make to pre-existing variables will remain once the block closes.
y = 20
1.times do
# put your code in here
i = 1
puts x = y # => 20, because y is available from outside the block
y = 'new value' # We can change the value of y but our changes will
# propagate to outside the block since y was defined before we opened
# the block.
end
defined? i # => nil, i is lost when you close the block
defined? x # => nil, x is also local to the block
puts y # => 'new value'
I want to test whether a equals 1 or 2
I could do
a == 1 || a == 2
but this requires repeating a (which would be annoying for longer variables)
I'd like to do something like a == (1 || 2), but obviously this won't work
I could do [1, 2].include?(a), which is not bad, but strikes me as a bit harder to read
Just wondering how do to this with idiomatic ruby
Your first method is idiomatic Ruby. Unfortunately Ruby doesn't have an equivalent of Python's a in [1,2], which I think would be nicer. Your [1,2].include? a is the nearest alternative, and I think it's a little backwards from the most natural way.
Of course, if you use this a lot, you could do this:
class Object
def member_of? container
container.include? self
end
end
and then you can do a.member_of? [1, 2].
I don't know in what context you're using this in, but if it fits into a switch statement you can do:
a = 1
case a
when 1, 2
puts a
end
Some other benefits is that when uses the case equality === operator, so if you want, you can override that method for different behavior. Another, is that you can also use ranges with it too if that meets your use case:
when 1..5, 7, 10
One way would be to petition "Matz" to add this functionality to the Ruby specification.
if input == ("quit","exit","close","cancel") then
#quit the program
end
But the case-when statement already lets you do exactly that:
case input when "quit","exit","close","cancel" then
#quit the program
end
When written on one line like that, it acts and almost looks like an if statement. Is the bottom example a good temporary substitution for the top example? You be the judge.
First put this somewhere:
class Either < Array
def ==(other)
self.include? other
end
end
def either(*these)
Either[*these]
end
Then, then:
if (either 1, 2) == a
puts "(i'm just having fun)"
end
You can just use intersection like
([a] & [1,2]).present?
a alternative way.
Include is definitely the way to go here. 🤝
%w[cat dog].include?(type)
a.to_s()=~/^(1|2)$/
Maybe I'm being thick here, but it seems to me that:
(1..2) === a
...works.