I'm trying to reduce the while loop below to a single line
def this_method(week)
i = 0
while i < array.length
yield(week[i])
i += 1
end
end
week.each do |week|
puts week
end
Like others, I'm confused about the example (array is not defined, and this_method is never called). But you certainly don't need the while loop. I'd just use the Integer#times method, since you're making no use of the array values:
array.length.times {|i| yield week[i]}
#each_index (which ram suggested) works just as well.
But if array is actually meant to be week, then it gets even simpler:
week.each {|x| yield x}
I'm not sure why you'd want to create a method that just recycles #each though.
For since line you can use Array#each_index:
array.each_index {|i| yield week[i] }
No, you can't. The ternary operator is a conditional expression, the while is a loop expression.
However, in Ruby you normally use enumerators, not while. Your code can be rewritten as
def this_method(week)
array.each_with_index { |item, i| yield(week[i]) }
end
What is not clear to me, is there the array variable comes from. Even in your example, there is no definition of such variable.
if in any form check conditions only once.
while on other hand, can check conditions many times.
Well, if you don't like other answers with enumerators you can use while in a different form:
def this_method(week)
i = -1
yield(week[i]) while (i+=1) < array.length
end
Related
I was trying to make my bubble sort shorter and I came up with this
class Array
def bubble_sort!(&block)
block = Proc.new { |a, b| a <=> b } unless block_given?
sorted = each_index.each_cons(2).none? do |i, next_i|
if block.call(self[i], self[next_i]) == 1
self[i], self[next_i] = self[next_i], self[i]
end
end until sorted
self
end
def bubble_sort(&prc)
self.dup.bubble_sort!(&prc)
end
end
I don't particularly like the thing with sorted = --sort code-- until sorted.
I just want to run the each_index.each_cons(s).none? code until it returns true. It's a weird situation that I use until, but the condition is a code I want to run. Any way, my try seems awkward, and ruby usually has a nice concise way of putting things. Is there a better way to do this?
This is just my opinion
have you ever read the ruby source code of each and map to understand what they do?
No, because they have a clear task expressed from the method name and if you test them, they will take an object, some parameters and then return a value to you.
For example if I want to test the String method split()
s = "a new string"
s.split("new")
=> ["a ", " string"]
Do you know if .split() takes a block?
It is one of the core ruby methods, but to call it I don't pass a block 90% of the times, I can understand what it does from the name .split() and from the return value
Focus on the objects you are using, the task the methods should accomplish and their return values.
I read your code and I can not refactor it, I hardly can understand what the code does.
I decided to write down some points, with possibility to follow up:
1) do not use the proc for now, first get the Object Oriented code clean.
2) split bubble_sort! into several methods, each one with a clear task
def ordered_inverted! (bubble_sort!), def invert_values, maybe perform a invert_values until sorted, check if existing methods already perform this sorting functionality
3) write specs for those methods, tdd will push you to keep methods simple and easy to test
4) If those methods do not belong to the Array class, include them in the appropriate class, sometimes overly complicated methods are just performing simple String operations.
5) Reading books about refactoring may actually help more then trying to force the usage of proc and functional programming when not necessary.
After looking into it further I'm fairly sure the best solution is
loop do
break if condition
end
Either that or the way I have it in the question, but I think the loop do version is clearer.
Edit:
Ha, a couple weeks later after I settled for the loop do solution, I stumbled into a better one. You can just use a while or until loop with an empty block like this:
while condition; end
until condition; end
So the bubble sort example in the question can be written like this
class Array
def bubble_sort!(&block)
block = Proc.new { |a, b| a <=> b } unless block_given?
until (each_index.each_cons(2).none? do |i, next_i|
if block.call(self[i], self[next_i]) == 1
self[i], self[next_i] = self[next_i], self[i]
end
end); end
self
end
def bubble_sort(&prc)
self.dup.bubble_sort!(&prc)
end
end
Is there a keyword I can use to explicitly tell the map function what the result of that particular iteration should be?
Consider:
a = [1,2,3,4,5]
a.map do |element|
element.to_s
end
In the above example element.to_s is implicitly the result of each iteration.
There are some situations where I don't want to rely on using the last executed line as the result, I would prefer to explicitly say what the result is in code.
For example,
a = [1,2,3,4,5]
a.map do |element|
if some_condition
element.to_s
else
element.to_f
end
end
Might be easier for me to read if it was written like:
a = [1,2,3,4,5]
a.map do |element|
if some_condition
result_is element.to_s
else
result_is element.to_f
end
end
So is there a keyword I can use in place of result_is?
return will return from the calling function, and break will stop the iteration early, so neither of those is what I'm looking for.
The last thing left on the stack is automatically the result of a block being called. You're correct that return would not have the desired effect here, but overlook another possibility: Declaring a separate function to evaluate the entries.
For example, a reworking of your code:
def function(element)
if (some_condition)
return element.to_s
end
element.to_f
end
a.map do |element|
function(element)
end
There is a nominal amount of overhead on calling the function, but on small lists it should not be an issue. If this is highly performance sensitive, you will want to do it the hard way.
Yes, there is, it's called next. However, using next in this particular case will not improve readability. On the contrary, it will a) confuse the reader and b) give him the impression that the author of that code doesn't understand Ruby.
The fact that everything is an expression in Ruby (there are no statements) and that every expression evaluates to the value of the last sub-expression in that expression are fundamental Ruby knowledge.
Just like return, next should only be used when you want to "return" from the middle of a block. Usually, you only use it as a guard clause.
The nature of map is to assign the last executed line to the array. Your last example is very similar to the following, which follows the expected behavior:
a = [1,2,3,4,5]
a.map do |element|
result = if some_condition
element.to_s
else
element.to_f
end
result
end
No, there is no language keyword in ruby you can use to determine the result mapped into the resulting array before executing other code within the iteration.
You may assign a variable which you then return when some other code has been executed:
a.map do |element|
result = some_condition ? element.to_s : element.to_f
#do something else with element
result
end
Keep in mind the reason for ruby not providing a keyword for this kind of code is that these patterns tend to have a really low readability.
taglist = [{:name=>"Daniel_Xu_Forever", :tag=>["helo", "world"]},
{:name=>"kcuf", :tag=>["hhe"]},
{:name=>"fine", :tag=>[]},
{:name=>"how hare you", :tag=>[]},
{:name=>"heki", :tag=>["1", "2", "3"]},
{:name=>"railsgirls", :tag=>[]},
{:name=>"_byoy", :tag=>[]},
{:name=>"ajha", :tag=>[]},
{:name=>"nimei", :tag=>[]}]
How to get specified name's tag from taglist
For example , I want to extract user "fine"'s tag?
Could this be achieved without do iterator?
This will return the contents of the :tag key for any users name which == 'fine'
taglist.select { |x| x[:name] == 'fine' }.map { |u| u[:tag] }
First you select out only the users you are interested with .select.
And then use .map to collect an array of only what you want.
In this case the end result will be: []
Is do really an iterator?
taglist.find{|tl| tl[:name] == 'fine'}[:tag]
Just to be silly how about:
eval taglist.to_s[/:name=>"fine", :tag=>(.*?)}/, 1]
#=> []
No, it cannot be done without a loop.
And even if you find a solution where your code avoids a loop, for sure the library function that you're calling will include a loop. Finding an element in an array requires a loop. Period.
For example, take this (contrived) example
pattern = "fine"
def pattern.===(h); self == h[:name]; end
taglist.grep(pattern)
which does not seem to use a loop, but calls grep which is implemented using a loop.
Or another, equally contrived, example
class Hash; def method_missing(sym); self[sym]; end; end
taglist.group_by(&:name)["fine"]
which again does seem to call group_by without a loop, but actually it does.
So the answer is, no.
So my first answer missed the no do rule.
Here is an answer that doesn't use a do block.
i=0
begin
if taglist[i][:name] == 'fine'
tag = taglist[i][:tag]
break
end
i+=1
end while i < taglist.length - 0
Technically I think this is still using a block. But probably satisfies the restriction.
I'm doing a SaaS course with Ruby. On an exercise, I'm asked to calculate the cartesian product of two sequences by using iterators, blocks and yield.
I ended up with this, by pure guess-and-error, and it seems to work. But I'm not sure about how. I seem to understand the basic blocks and yield usage, but this? Not at all.
class CartProd
include Enumerable
def initialize(a,b)
#a = a
#b = b
end
def each
#a.each{|ae|
#b.each{|be|
yield [ae,be]
}
}
end
end
Some explanation for a noob like me, please?
(PS: I changed the required class name to CartProd so people doing the course can't find the response by googling it so easily)
Let's build this up step-by-step. We will simplify things a bit by taking it out of the class context.
For this example it is intuitive to think of an iterator as being a more-powerful replacement for a traditional for-loop.
So first here's a for-loop version:
seq1 = (0..2)
seq2 = (0..2)
for x in seq1
for y in seq2
p [x,y] # shorthand for puts [x, y].inspect
end
end
Now let's replace that with more Ruby-idiomatic iterator style, explicitly supplying blocks to be executed (i.e., the do...end blocks):
seq1.each do |x|
seq2.each do |y|
p [x,y]
end
end
So far, so good, you've printed out your cartesian product. Now your assignment asks you to use yield as well. The point of yield is to "yield execution", i.e., pass control to another block of code temporarily (optionally passing one or more arguments).
So, although it's not really necessary for this toy example, instead of directly printing the value like above, you can yield the value, and let the caller supply a block that accepts that value and prints it instead.
That could look like this:
def prod(seq1, seq2)
seq1.each do |x|
seq2.each do |y|
yield [x,y]
end
end
end
Callable like this:
prod (1..2), (1..2) do |prod| p prod end
The yield supplies the product for each run of the inner loop, and the yielded value is printed by the block supplied by the caller.
What exactly do you not understand here? You've made an iterator that yields all possible pairs of elements. If you pass CartProd#each a block, it will be executed a.length*b.length times. It's like having two different for cycles folded one into another in any other programming language.
yield simply passes (yields) control to a block of code that has been passed in as part of the method call. The values after the yield keyword are passed into the block as arguments. Once the block has finished execution it passes back control.
So, in your example you could call #each like this:
CartProd.new([1, 2], [3, 4]).each do |pair|
# control is yielded to this block
p pair
# control is returned at end of block
end
This would output each pair of values.
In a discussion of Ruby loops, Niklas B. recently talked about for loop 'not introducing a new scope', as compared to each loop. I'd like to see some examples of how does one feel this.
O.K., I expand the question: Where else in Ruby do we see what apears do/end block delimiters, but there is actually no scope inside? Anything else apart from for ... do ... end?
O.K., One more expansion of the question, is there a way to write for loop with curly braces { block } ?
Let's illustrate the point by an example:
results = []
(1..3).each do |i|
results << lambda { i }
end
p results.map(&:call) # => [1,2,3]
Cool, this is what was expected. Now check the following:
results = []
for i in 1..3
results << lambda { i }
end
p results.map(&:call) # => [3,3,3]
Huh, what's going on? Believe me, these kinds of bugs are nasty to track down. Python or JS developers will know what I mean :)
That alone is a reason for me to avoid these loops like the plague, although there are more good arguments in favor of this position. As Ben pointed out correctly, using the proper method from Enumerable almost always leads to better code than using plain old, imperative for loops or the fancier Enumerable#each. For instance, the above example could also be concisely written as
lambdas = 1.upto(3).map { |i| lambda { i } }
p lambdas.map(&:call)
I expand the question: Where else in Ruby do we see what apears do/end block delimiters, but there is actually no scope inside? Anything else apart from for ... do ... end?
Every single one of the looping constructs can be used that way:
while true do
#...
end
until false do
# ...
end
On the other hand, we can write every one of these without the do (which is obviously preferrable):
for i in 1..3
end
while true
end
until false
end
One more expansion of the question, is there a way to write for loop with curly braces { block }
No, there is not. Also note that the term "block" has a special meaning in Ruby.
First, I'll explain why you wouldn't want to use for, and then explain why you might.
The main reason you wouldn't want to use for is that it's un-idiomatic. If you use each, you can easily replace that each with a map or a find or an each_with_index without a major change of your code. But there's no for_map or for_find or for_with_index.
Another reason is that if you create a variable within a block within each, and it hasn't been created before-hand, it'll only stay in existance for as long as that loop exists. Getting rid of variables once you have no use for them is a good thing.
Now I'll mention why you might want to use for. each creates a closure for each loop, and if you repeat that loop too many times, that loop can cause performance problems. In https://stackoverflow.com/a/10325493/38765 , I posted that using a while loop rather than a block made it slower.
RUN_COUNT = 10_000_000
FIRST_STRING = "Woooooha"
SECOND_STRING = "Woooooha"
def times_double_equal_sign
RUN_COUNT.times do |i|
FIRST_STRING == SECOND_STRING
end
end
def loop_double_equal_sign
i = 0
while i < RUN_COUNT
FIRST_STRING == SECOND_STRING
i += 1
end
end
times_double_equal_sign consistently took 2.4 seconds, while loop_double_equal_sign was consistently 0.2 to 0.3 seconds faster.
In https://stackoverflow.com/a/6475413/38765 , I found that executing an empty loop took 1.9 seconds, whereas executing an empty block took 5.7 seconds.
Know why you wouldn't want to use for, know why you would want to use for, and only use the latter when you need to. Unless you feel nostalgic for other languages. :)
Well, even blocks are not perfect in Ruby prior to 1.9. They don't always introduce new scope:
i = 0
results = []
(1..3).each do |i|
results << lambda { i }
end
i = 5
p results.map(&:call) # => [5,5,5]