Search code examples
rubyfunctioncombinationspermutation

What is the most Ruby-like way of generating every unique combination of 3 positive integers that add up to 100


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]
]

Solution

  • 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