I have issue with technically deep question about loops in ruby.
I have algorithm that is executed sequentially for array of Boolean values and operate on one data structures.
def function(boolean, data_structure)
The key point is that the order of execution is most important thing because expression
function(true, data_structure);function(true, data_structure); function(false, data_structure)
will leave other result in data structure than expression
function(true, data_structure);function(false, data_structure); function(true, data_structure)
I spent some time trying with each loop, but I didn't get any problems as other result in data structure due execution similar expression as follow
[true, true, false ....].each do |value| function(value, data_structure) end
My question: in default ruby configuration is my each loop is the same like followed for loop?
for i in 0..array.size do function(array[i], data_structure) end
Because each loop makes the code much clearer and easier to modify and I was thinking about leave each expression rather than using for loop.
(Of course in my case I have a lot more code rather than calling only function()..)
Yes, it's identical. It will loop through the elements of the array, in order.
Related
Often when programming in Ruby, I find myself writing small for loops with a single statement in the body. For example...
for number in 1..10
puts number
end
In other languages like C, Java or Kotlin (for example), I'd be able to write the same code in two lines. For example...
// Kotlin
for (number in 1..10)
println(number)
In the above example, the ending of the loop body is inferred due to the lack of curly braces.
Does Ruby have a way to imitate this "single-statement" style of "for loop"?
Here are some of [my options/your potential replies], along with my thoughts on them.
You could append ; end to the body to end it on the same line.
This is true, and pretty sufficient, but I'd like to know if there's a more idiomatic approach.
This seems unnecessarily picky. Why would you ever want to do this?
You may think I'm being too picky. You may also think what I'm trying to do is un-idiomatic (if that's even a word). I totally understand, but I'd still love to know if it's do-able!
Doing this could let us write code that's even just a tiny bit nicer to read. And for programmers, readability matters.
Sure, you're looking for each, Range#each in this particular case:
(1..10).each { |number| puts number }
For more complex iterations use do - end block syntax. For example
(1..10).each do |number|
puts number
some_method_call(number)
Rails.logger.info("The #{number} is used")
something_else
end
To find more check out Ruby documentation, in particular, see Enumerable.
There is a vanishingly tiny number of cases, where any self-respecting Ruby programmer would even write an explicit loop at all. The number of cases where that loop is a for loop is exactly zero. There is no "more idiomatic" way to write a for loop, because for loops are non-idiomatic, period.
There is an even shorter syntax.
If you are just calling one method on each object you can use & syntax.
(1..3).collect(&:odd?) # => [true, false, true]
This is the same as
(1..3).collect { |each| each.odd? } # => [true, false, true]
This is the preferred way of writing loops in Ruby.
You'll quickly get used to both & and {} block syntax and the enumeration methods defined in Enumerable module. Some useful methods are
each which evaluates the block for each element
collect which create new array with the result from each block
detect which returns the first element for which block results true
select which create new array with elements for which block results true
inject which applies "folding" operation, eg sum = (1..10).inject { |a, b| a + b }
Fun fact, style guides for production code usually ban for loops at all because of a subtle but dangerous scoping issue. See more here, https://stackoverflow.com/a/41308451/24468
If someone could shed a light for me, or show an equivalent (if one exists) in PHP-style code, I'd really love it.
This piece of code:
require 'sqlite3'
SQLite3::Database.new("metadata.db").execute("SELECT * from BOOKS") do |row|
puts row
end
uses execute method to issue an SQL query. It's doing a loop, but on what? On the returned value of that query? Can you append a block of code to any expression and it will work on its return value? It seems like the loop isn't connected to anything, and |row| appears from nowhere.
For comparison, in PHP to access a database I would write
$db = new mysqli('details');
$results = $db->query("SELECT * FROM books");
while ($row = $results->fetch()) {
echo $row[0];
}
which says to create a database, store the results of a query as results, then start a loop in which each row of that result is turned into an array to be accessed with array notation. Is that not how Rubyists would do it? What's going on here?
It's doing a loop, but on what? On the returned value of that query?
Right. In your example row is whatever is generated by
SQLite3::Database.new("metadata.db").execute("SELECT * from BOOKS")
In this case row a reasonable thing to call this because any actions you do in the block will be based on that row from the db, but you can choose to call this 'block argument' anything you want.
Is this a thing that happens in Ruby, where you can immediately append a block of code to any expression and it'll work on its return value?
Not really, no. There are some methods that take block arguments - each is a good example.
If you have a collection of, say, cats at the animal hospital, you can loop through them and do operations on each cat because each takes a block argument.
#pretend these cats are objects and not just a string name
cats = [ "mrs. muffin face", "princess cupcake", "deathlord 666", ...]
cats.each do |cat|
#do stuff with each cat here. print their name, find their shoe size, etc
end
Blocks are a very fundamental ruby concept, so it's probably worth reading a bit more about them - this answer links to Why's (poignant) guide to ruby which is generally a good basic reference. I would also suggest Eloquent Ruby for more thorough examples of Ruby.
You seem to be assuming that a block is something that loops on a result, but that is not necessarily correct. A block in Ruby is opposed to arguments. Whereas arguments are evaluated before the execution of the main method, a block is not evaluated in advance. Whether to evaluate that block, under what bindings it is to be evaluated, what timing it is to be evaluated, and how many times it is to be evaluated, all is up to the main method. The block variable in | | is a parameter that the main method passes to the block. Often, elements of the value the main method would have returned without the block are passed one after another, which is the case you had in mind, but that is not always the case.
Here is how execute might be coded in Ruby
class SQLite3::Database
def execute(query_str)
results = db.query(query_str)
while (row = results.fetch)
yield row
end
end
end
(assuming db.query and results.fetch work as you would expect from PHP). As you can see, this is nearly identical to what you're used to from PHP except for that weird yield. As the method loops through the rows of the result, yield passes each row to the block.
This lets you focus on the important stuff (what to do with each row) while hiding away the incidental details (like iterating over a result variable).
I'm learning ruby and have a few questions about some code I wrote for a newbie challenge. Purpose of challenge is to find country with largest population from an xml document.
I've included my code below. Questions I have are:
Is there a way to avoid having to initialize the #max_pop variable (#max_pop=0)?
Is there shorthand for combining the entire conditional block into 1 line?
Do I have to use instance vars #max_pop, #max_pop_country? Got error without them.
Which is more efficient:
Loop through each country and check if pop > max_pop (approach in code below)
Create pop hash (pop[:country]) and then find country with highest pop
Is there hash method to return key value pair for largest element in hash (to do 4.1)?
Source Code:
#max_pop=0
doc.elements.each("cia/country") do |country|
if country.attributes["population"].to_i > #max_pop
#max_pop=country.attributes["population"].to_i
#max_pop_country=country.attributes["name"]
end
end
puts "country with largest pop is #{#max_pop_country} with pop of #{#max_pop}
I am not familiar with rexml, but you ought to be able to simplify everything to something like this:
max_pop_elem = doc.elements.enum_for(:each, "cia/country").max_by { |c| c.attributes["population"].to_i }
max_pop_country = max_pop_elem.attributes["name"]
max_pop = max_pop_elem.attributes["population"].to_i
Yes, see above.
Yes, see above.
No. You should use local variables instead of instance variables when possible.
Don't worry about efficiency of CPU time until you have a slow program. Then use ruby-prof. Until then, just worry about the efficiency of coding time (do things the easy way).
Yes, just do key, value = hash.max_by{|k,v| v}.
In general, if you are going to be iterating over things you should learn about Ruby's Enumerable module. I made a reference sheet for it here.
As is stated in the title, I was curious to know why Ruby decided to go away from classical for loops and instead use the array.each do ...
I personally find it a little less readable, but that's just my personal opinion. No need to argue about that. On the other hand, I suppose they designed it that way on purpose, there should be a good reason behind.
So, what are the advantages of putting loops that way? What is the "raison d'etre" of this design decision?
This design decision is a perfect example of how Ruby combines the object oriented and functional programming paradigms. It is a very powerful feature that can produce simple readable code.
It helps to understand what is going on. When you run:
array.each do |el|
#some code
end
you are calling the each method of the array object, which, if you believe the variable name, is an instance of the Array class. You are passing in a block of code to this method (a block is equivalent to a function). The method can then evaluate this block and pass in arguments either by using block.call(args) or yield args. each simply iterates through the array and for each element it calls the block you passed in with that element as the argument.
If each was the only method to use blocks, this wouldn't be that useful but many other methods and you can even create your own. Arrays, for example have a few iterator methods including map, which does the same as each but returns a new array containing the return values of the block and select which returns a new array that only contains the elements of the old array for which the block returns a true value. These sorts of things would be tedious to do using traditional looping methods.
Here's an example of how you can create your own method with a block. Let's create an every method that acts a bit like map but only for every n items in the array.
class Array #extending the built in Array class
def every n, &block #&block causes the block that is passed in to be stored in the 'block' variable. If no block is passed in, block is set to nil
i = 0
arr = []
while i < self.length
arr << ( block.nil? ? self[i] : block.call(self[i]) )#use the plain value if no block is given
i += n
end
arr
end
end
This code would allow us to run the following:
[1,2,3,4,5,6,7,8].every(2) #= [1,3,5,7] #called without a block
[1,2,3,4,5,6,7,8,9,10].every(3) {|el| el + 1 } #= [2,5,8,11] #called with a block
Blocks allow for expressive syntax (often called internal DSLs), for example, the Sinatra web microframework.
Sinatra uses methods with blocks to succinctly define http interaction.
eg.
get '/account/:account' do |account|
#code to serve of a page for this account
end
This sort of simplicity would be hard to achieve without Ruby's blocks.
I hope this has allowed you to see how powerful this language feature is.
I think it was mostly because Matz was interested in exploring what a fully object oriented scripting language would look like when he built it; this feature is based heavily on the CLU programming language's iterators.
It has turned out to provide some interesting benefits; a class that provides an each method can 'mix in' the Enumerable module to provide a huge variety of pre-made iteration routines to clients, which reduces the amount of tedious boiler-plate array/list/hash/etc iteration code that must be written. (Ever see java 4 and earlier iterators?)
I think you are kind of biased when you ask that question. Another might ask "why were C for loops designed that way?". Think about it - why would I need to introduce counter variable if I only want to iterate through array's elements? Say, compare these two (both in pseudocode):
for (i = 0; i < len(array); i++) {
elem = array[i];
println(elem);
}
and
for (elem in array) {
println(elem);
}
Why would the first feel more natural than the second, except for historical (almost sociological) reasons?
And Ruby, highly object-oriented as is, takes this even further, making it an array method:
array.each do |elem|
puts elem
end
By making that decision, Matz just made the language lighter for superfluous syntax construct (foreach loop), delegating its use to ordinary methods and blocks (closures). I appreciate Ruby the most just for this very reason - being really rational and economical with language features, but retaining expressiveness.
I know, I know, we have for in Ruby, but most of the people consider it unneccessary.
The do ... end blocks (or { ... }) form a so-called block (almost a closure, IIRC). Think of a block as an anonymous method, that you can pass as argument to another method. Blocks are used a lot in Ruby, and thus this form of iteration is natural for it: the do ... end block is passed as an argument to the method each. Now you can write various variations to each, for example to iterate in reverse or whatnot.
There's also the syntactic sugar form:
for element in array
# Do stuff
end
Blocks are also used for example to filter an array:
array = (1..10).to_a
even = array.select do |element|
element % 2 == 0
end
# "even" now contains [2, 4, 6, 8, 10]
I think it's because it emphasizes the "everything is an object" philosophy behind Ruby: the each method is called on the object.
Then switching to another iterator is much smoother than changing the logic of, for example, a for loop.
Ruby was designed to be expressive, to read as if it was being spoken... Then I think it just evolved from there.
This comes from Smalltalk, that implements control structures as methods, thus reducing the number of keywords and simplifying the parser. Thus allowing controll strucures to serve as proff of concept for the language definition.
In ST, even if conditions are methods, in the fashion:
boolean.ifTrue ->{executeIfBody()}, :else=>-> {executeElseBody()}
In the end, If you ignore your cultural bias, what will be easier to parse for the machine will also be easier to parse by yourself.
In C#, you could do something like this:
public IEnumerable<T> GetItems<T>()
{
for (int i=0; i<10000000; i++) {
yield return i;
}
}
This returns an enumerable sequence of 10 million integers without ever allocating a collection in memory of that length.
Is there a way of doing an equivalent thing in Ruby? The specific example I am trying to deal with is the flattening of a rectangular array into a sequence of values to be enumerated. The return value does not have to be an Array or Set, but rather some kind of sequence that can only be iterated/enumerated in order, not by index. Consequently, the entire sequence need not be allocated in memory concurrently. In .NET, this is IEnumerable and IEnumerable<T>.
Any clarification on the terminology used here in the Ruby world would be helpful, as I am more familiar with .NET terminology.
EDIT
Perhaps my original question wasn't really clear enough -- I think the fact that yield has very different meanings in C# and Ruby is the cause of confusion here.
I don't want a solution that requires my method to use a block. I want a solution that has an actual return value. A return value allows convenient processing of the sequence (filtering, projection, concatenation, zipping, etc).
Here's a simple example of how I might use get_items:
things = obj.get_items.select { |i| !i.thing.nil? }.map { |i| i.thing }
In C#, any method returning IEnumerable that uses a yield return causes the compiler to generate a finite state machine behind the scenes that caters for this behaviour. I suspect something similar could be achieved using Ruby's continuations, but I haven't seen an example and am not quite clear myself on how this would be done.
It does indeed seem possible that I might use Enumerable to achieve this. A simple solution would be to us an Array (which includes module Enumerable), but I do not want to create an intermediate collection with N items in memory when it's possible to just provide them lazily and avoid any memory spike at all.
If this still doesn't make sense, then consider the above code example. get_items returns an enumeration, upon which select is called. What is passed to select is an instance that knows how to provide the next item in the sequence whenever it is needed. Importantly, the whole collection of items hasn't been calculated yet. Only when select needs an item will it ask for it, and the latent code in get_items will kick into action and provide it. This laziness carries along the chain, such that select only draws the next item from the sequence when map asks for it. As such, a long chain of operations can be performed on one data item at a time. In fact, code structured in this way can even process an infinite sequence of values without any kinds of memory errors.
So, this kind of laziness is easily coded in C#, and I don't know how to do it in Ruby.
I hope that's clearer (I'll try to avoid writing questions at 3AM in future.)
It's supported by Enumerator since Ruby 1.9 (and back-ported to 1.8.7). See Generator: Ruby.
Cliche example:
fib = Enumerator.new do |y|
y.yield i = 0
y.yield j = 1
while true
k = i + j
y.yield k
i = j
j = k
end
end
100.times { puts fib.next() }
Your specific example is equivalent to 10000000.times, but let's assume for a moment that the times method didn't exist and you wanted to implement it yourself, it'd look like this:
class Integer
def my_times
return enum_for(:my_times) unless block_given?
i=0
while i<self
yield i
i += 1
end
end
end
10000.my_times # Returns an Enumerable which will let
# you iterate of the numbers from 0 to 10000 (exclusive)
Edit: To clarify my answer a bit:
In the above example my_times can be (and is) used without a block and it will return an Enumerable object, which will let you iterate over the numbers from 0 to n. So it is exactly equivalent to your example in C#.
This works using the enum_for method. The enum_for method takes as its argument the name of a method, which will yield some items. It then returns an instance of class Enumerator (which includes the module Enumerable), which when iterated over will execute the given method and give you the items which were yielded by the method. Note that if you only iterate over the first x items of the enumerable, the method will only execute until x items have been yielded (i.e. only as much as necessary of the method will be executed) and if you iterate over the enumerable twice, the method will be executed twice.
In 1.8.7+ it has become to define methods, which yield items, so that when called without a block, they will return an Enumerator which will let the user iterate over those items lazily. This is done by adding the line return enum_for(:name_of_this_method) unless block_given? to the beginning of the method like I did in my example.
Without having much ruby experience, what C# does in yield return is usually known as lazy evaluation or lazy execution: providing answers only as they are needed. It's not about allocating memory, it's about deferring computation until actually needed, expressed in a way similar to simple linear execution (rather than the underlying iterator-with-state-saving).
A quick google turned up a ruby library in beta. See if it's what you want.
C# ripped the 'yield' keyword right out of Ruby- see Implementing Iterators here for more.
As for your actual problem, you have presumably an array of arrays and you want to create a one-way iteration over the complete length of the list? Perhaps worth looking at array.flatten as a starting point - if the performance is alright then you probably don't need to go too much further.