Ruby: How to iterate over a range, but in set increments?
See http://ruby-doc.org/core/classes/Range.html#M000695 for the full API.
Basically you use the step()
method. For example:
(10..100).step(10) do |n|
# n = 10
# n = 20
# n = 30
# ...
end
how implement a function to iterate over if its passed a Range
One technique, that changes very little of this implementation, would be to convert your range to an array.
module Enumerable
def my_each
return to_enum :my_each unless block_given?
index = 0
while index < size
if is_a? Array
yield self[index]
elsif is_a? Hash
yield keys[index], self[keys[index]]
elsif is_a? Range
yield to_a[index]
end
index += 1
end
end
end
r_list = (1..10)
puts r_list.my_each { |number| puts number }
Result:
1
2
3
4
5
6
7
8
9
10
How to change the amount a for loop increments in Ruby?
You want to use step
(0..9).step(3) do |i|
puts i
end
Iterate set covered by cross-product of ranges in ruby
There are two orthogonals tasks, try not to to mix them up so the code remains modular.
How to build a cartesian product of N arrays.
How to filter the product and count.
Use Array#product to get the cartesian product:
xs = [0..1, 0..1, 0..1].map(&:to_a)
xss = xs[0].product(*xs[1..-1]) # or xs.first.product(*xs.drop(1))
#=> [[0, 0, 0], [0, 0, 1], [0, 1, 0], ..., [1, 1, 0], [1, 1, 1]]
And now do the filter and couting:
xss.count { |x, y, z| x == 1 && z == 0 }
#=> 2
This is slightly uglier that it should, that's because we'd need the classmethod Array::product
instead of the method Array#product
. No problem, let's add it into our extensions module and finally write:
Array.product(0..1, 0..1, 0..1).count { |x, y, z| x == 1 && z == 0 }
#=> 2
How do I effectively iterate over a large records and create a new list?
Right now you are loading all the documents in memory and doing a ton of N+1 queries.
Below are some ideas. The code is not tested at all.
So, if we are talking about more that 1k records then you can use find_each.
Note: This method is only intended to use for batch processing of large amounts of records that wouldn’t fit in memory all at once. If you just need to loop over less than 1000 records, it’s probably better just to use the regular find methods.
Then, inside that loop you are doing N+1. It's best to create some associations and eager_load
them.
# Example
has_many :reconciled, -> { where(status: true) }, class_name: 'PrimaryFile'
has_many :unreconciled, -> { where(status: false) }, class_name: 'PrimaryFile'
And finally (untested !):
files = []
Document.includes(:reconciled, :unreconciled).find_each do |doc|
reconciled = doc.reconciled.map(&:amount_credit).sum // for eager loading
unreconciled = doc.unreconciled.map(&:amount_credit).sum
files.push({...})
end
You could also eager_load
just :primary_files
and get the reconciled
and unreconciled
by filtering the doc.primary_files
array to get the sum. This way you eager_load just one relation instead of 3. It's up to you.
Document.includes(:primary_files).find_each do |doc|
reconciled = doc.primary_files.select { |pf| pf.active }.sum(&:amount_credit)
...
end
Make sure when you run the loop you have NO N+1 queries.
How to iterate over all but first element of an enumerable
How about this?
[1,2,3].drop(1).each {|x| puts x }
# >> 2
# >> 3
Here's how you can continue walking the iterator
a = [1,2,3]
b = a.each # => #<Enumerator: [1, 2, 3]:each>
b.next # skip first one
loop do
c = b.next
puts c
end
# >> 2
# >> 3
A better method to iterate over an array and object attributes?
def mymethod
params = {'foo'=>:blue,'bar'=>:red,'jaa'=>:yellow}
params.each do |k,v|
my_object.send(v).push(collect_method(k))
end
end
where collect_method is another method in Myobject class
What is a stable way to iterate on a range with custom step?
Rust 1.28+
Iterator::step_by
is now stable:
fn main() {
for i in (0..100).step_by(2) {
println!("{}", i);
}
}
Rust 1.1+
You can always write it out the old-fashioned way:
fn main() {
let mut i = 0;
while i < 100 {
println!("i: {}", i);
i += 2;
}
}
Which can then be abstracted:
use std::ops::Add;
fn step_by<T, F>(start: T, end_exclusive: T, step: T, mut body: F)
where
T: Add<Output = T> + PartialOrd + Copy,
F: FnMut(T),
{
let mut i = start;
while i < end_exclusive {
body(i);
i = i + step;
}
}
fn main() {
step_by(0, 100, 2, |i| {
println!("i: {}", i);
})
}
Interesting historical side note, I believe that originally all the looping was done with closures like this, before iterators became extremely prevalent.
You can then take this and make it into an iterator:
use std::ops::Add;
struct StepBy<T> {
start: T,
end_exclusive: T,
step: T,
}
impl<T> StepBy<T> {
fn new(start: T, end_exclusive: T, step: T) -> Self {
Self {
start,
end_exclusive,
step,
}
}
}
impl<T> Iterator for StepBy<T>
where
T: Add<Output = T> + PartialOrd + Copy,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.start < self.end_exclusive {
let v = self.start;
self.start = self.start + self.step;
Some(v)
} else {
None
}
}
}
fn main() {
for i in StepBy::new(0, 100, 2) {
println!("i: {}", i);
}
}
See also:
- How can I add new methods to Iterator?
Best way to iterate over a sequence and change one object at a time (Ruby)
Use Array#each:
self.answers.each {|a| a.some_attr = some_val if a.some_criteria}
Related Topics
"Whenever" Gem Running Cron Jobs on Heroku
Redefining a Single Ruby Method on a Single Instance with a Lambda
Using Join Tables in Ruby on Rails
How to Check If a Value Is a Number
What Does the "$" Character Mean in Ruby
How to Use Hash Keys as Methods on a Class
Yaml How Many Spaces Per Indent
How to Add Migration with Multiple References to the Same Model in One Table? Ruby/Rails
Finding the Element of a Ruby Array with the Maximum Value for a Particular Attribute
Put a Link in a Flash[:Notice]
In Ruby on Rails, After Send_File Method Delete the File from Server
How to Reference a Function in Ruby
Couldn't Require Openssl in Ruby