Reputation: 7815
The thing I love about Ruby is its elegance: if we use inject
or map
along with take_while
and select
, we can chain blocks together to achieve a lot while writing little.
Sticking with the idea of single line solutions, how would one write a nested for
loop in Ruby without writing the entire nested for
loop? I feel it must be possible, I just can't for the life of me figure out what it is. I am looking for something like this:
10.times {|a| 10.times {|b| a*b}}
The only solution I can come up with that is at all elegant is nested for
loops. Does anyone have a better solution?
array = []
for a in (1..10)
for b in (1..10)
array << a*b
end
end
Upvotes: 3
Views: 735
Reputation: 48599
The only solution I can come up with that is at all elegant is nested for loops
for-in
loops call each()
on the object to the right of in
, so rubyists don't use for-in
loops--they call each()
directly on the object:
array = []
(1..10).each do |a|
(1..3).each do |b|
array << a*b
end
end
Sticking with the idea of single line solutions
Doing that will nearly guarantee you don't write elegant ruby code--just look at the proposed solutions.
Upvotes: 3
Reputation: 30445
Looking at all the answers to this question, I don't feel any of them appear more "elegant" or easier to read than the OP's nested for
loops. If you want a less verbose notation for nested iteration, I don't think you'll do better than defining your own shorthand. Something like:
module Enumerable
def combinations(*others)
return enum_for(:combinations,*others) if not block_given?
return if self.empty?
if others.empty?
self.each { |x| yield [x] }
else
others.first.combinations(*others.drop(1)) { |a| self.each { |x| yield (a + [x]) }}
end
end
end
Having defined this utility method, you can write your example of nested iteration as:
array = []
(1..10).combinations(1..10) { |a,b| array << a*b }
Upvotes: 1
Reputation: 12578
Facing problems like these, remember your high school calculus:
a = *1..10
b = *1..10
require 'matrix'
Matrix.column_vector( a ) * Matrix[ b ]
# or equivalent
Matrix[ a ].transpose * Matrix[ b ]
Matrix is a part of Ruby stdlib and every serious Ruby speaker should learn its interface.
Upvotes: 0
Reputation: 62648
Array has some cool methods.
Array(1..10).repeated_permutation(2).map {|a, b| a*b }
#repeated_permutation
will take an array and generate an array of all permutations of that array of a given length (2, in this case), permitting for repetition (ie, [1,1]
). We can then just map the product of each pair into a final array.
You can generalize this by using inject(:*)
. This will take the resultant permutations and multiply all the elements of each. For example, to generate (1*1*1*1)..(10*10*10*10)
(resulting in an output set of 10,000 elements!):
Array(1..10).repeated_permutation(4).map {|v| v.inject :*}
Upvotes: 7
Reputation: 2194
(1..10).inject([]) { |result,a| result + (1..10).to_a.map { |b| a*b } }
Or
def arithmetic(range, &block)
range.inject([]) { |result,a| result + range.to_a.map { |b| block.call(a,b) } }
end
range = (1..10)
arithmetic(range) {|a,b| a*b }
arithmetic(range) {|a,b| a+b }
Upvotes: 0
Reputation: 368954
(1..10).to_a.product((1..10).to_a).map { |a,b| a*b }
http://ruby-doc.org/core-2.0/Array.html#method-i-product
Upvotes: 4