Conditions:
a + b + c = 100
a,b,c positive integers or 0
Desired output:
[
[0,0,100],
[0,1,99 ],
... # all other permutations
[99,1,0 ],
[100,0,0]
]
I'd write:
(0..100).flat_map { |x| (0..100-x).map { |y| [x, y, 100-x-y] } }
#=> [[0, 0, 100], [0, 1, 99]], ..., [99, 1, 0], [100, 0, 0]]
Site note 1: this is a classical example where list-comprehensions shine (and even more if there were a condition somewhere). Since Ruby has no LC we have to do the typical conversion to OOP: N-1 flat_map
's + 1 map
. It would be awesome to have LCs in Ruby (check this feature request), Scala has proven that even a pure OOP language greatly benefits from this syntactic sugar (though I can understand prevention from the devs because of the implicit iterable protocol/method). On an imaginary Ruby that supported them you'd write:
[[x, y, 100-x-y] for x in 0..100 for y in 0..100-x] # imaginary Ruby
Side note 2: Imagine that you prefer a less memory-consuming solution (you probably don't need the whole array). A lazy solution with Ruby 2.0 requires just to add a couple of [lazy][2]
proxies:
(0..100).lazy.flat_map { |x| (0..100-x).lazy.map { |y| [x, y, 100-x-y] } }
Side note 3: Just for completeness, in the line of @akuhn answer, another lazy solution using enumerators:
Enumerator.new do |e|
(0..100).each { |x| (0..100-x).each { |y| e.yield([x, y, 100-x-y]) } }
end
Here's my solution
for a in 0..100; for b in 0..100-a; p [a,b,100-a-b]; end; end
which I find reads almost like @tokland’s list comprehension. If you like to use the values further downstream rather than printing them, put the code in a generator method
def generate
return enum_for(:generate) unless block_given?
for a in 0..100
for b in 0..100-a
yield [a,b,100-a-b]
end
end
end
which is then used as in
generate { |a,b,c| puts [a,b,c] }
or as in
generate { |each| p each }
or as in
p generate.to_a
which all print all generated tuples.
I'd say the most Ruby-ish way (which is not by any means the most efficient way) is this:
(0..100).to_a.repeated_permutation(3).find_all{|triplet|triplet.inject(:+)==100}
The only non-transparent part of this chain is the to_a
, which converts the range object given by (0..100) to an array (ranges are lazy, which doesn't work with repeated_permutation
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With