4

I'm trying to generate the set of sequences as shown below, not in any particularly order, but here its shown as a descending sequence. Note that each sequence also descends as I'm interested in combinations, not permutations. I'd like to store each sequence as an array..or the set of sequences as an array of arrays more preferably, but first things first.

6                   
5   1               
4   2               
4   1   1           
3   3               
3   2   1           
3   1   1   1       
2   2   2           
2   2   1   1       
2   1   1   1   1   
1   1   1   1   1   1

Right now I am simply focusing on generating these sets and I'm trying to do it recursively. Essentially..these are all the sequences of numbers when combines will give some total..in this case 6. But notice how when the first number is 3, the set of numbers which follows is simply the set of sequences that gives a total of 3. In other words 6(target total) - 3 (first number) = 3 (set of sequences that give total of 3). Thus, should be able to do this recursively.

I tried to code as follows (and yes, this is my first language and yes, I've only been studying for about a week so I'm sure its all screwed up) but so far no luck. I think if I can just get the very core of the recursion working and put the values of all the objects to the screen so I can trace it line by line, I think I can move ahead, but between the logic and the syntax, I'm at a stand still.

My logic is:

  • define a method that passes 'count' representing the total being targeted.
  • create an array which is going to hold a given sequence of values
  • create an index which represents the position in the array (ignoring zero position).
  • define 'delta' and initialize it to the value of 'count' and have it represent the remaining target sum of the rest of the array. (since there is nothing in the array initially, the delta is the same as the count.)

Then, cycle through the possibilities for the next(first) value of the sequence starting from 1 and ending, obviously, with the maximum possible, which is the value of 'count' itself. Determine the new delta for each value in the cycle.

If the delta is 0, you are done otherwise determine this new sequence which will give this new delta. Likely need to append the new sequence to the current sequence as well.

i=0

    def seq(count)
        cvc=Array.new  # array to hold the number values
        i=i+1  # position index for the array
        puts 'i is ' + i.to_s
        delta=count 
        puts ' delta is ' + delta.to_s

        for value in 1..delta do  # value represents the number value
                cvc[i]=value
                puts 'cvc[i] is ' + cvc[i].to_s
                delta = delta-cvc.sum
                puts 'new delta is '+ delta.to_s
            if delta >1  then count=delta
                    seq(count)
            end
        end
    end
casperOne
  • 73,706
  • 19
  • 184
  • 253
user1212
  • 41
  • 3
  • If you select your code and then hit the `{}` button in the editor's toolbar, it'll prepend four spaces before every line and give you the code formatting. – sarnold Jun 04 '12 at 22:47
  • Incidentally, `i` will not have a value when this function runs so `i=i+1` will blow up; is there a supporting `i` definition elsewhere in the program? – sarnold Jun 04 '12 at 22:48
  • i was just going to initialize i to zero, i=0..to start it off...I will edit above to include – user1212 Jun 04 '12 at 22:50
  • also...I saw array.sum as a viable method..but it looks like its not supported in my base configuration..i think i need a require statement – user1212 Jun 04 '12 at 22:54
  • For the specific case of an array sum, I'd probably use the [`inject` method](http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-inject) that implements the [fold higher-order function](http://en.wikipedia.org/wiki/Fold_%28higher-order_function%29). It's a bit complicated but the upside is that once you're familiar with it, you can get a sum or a product or anything else you require very quickly: `cvc.inject(0) { |sum, element| sum+=element } ==> 3` (when I initialized `cvc` to three simple elements..) – sarnold Jun 04 '12 at 23:05
  • reading on these topics now..going to take a while to absorb..thks for help!! – user1212 Jun 04 '12 at 23:12

1 Answers1

6

Here's a solution:

def expand(n, max = n)
  return [[]] if n == 0
  [max, n].min.downto(1).flat_map do |i|
    expand(n-i, i).map{|rest| [i, *rest]}
  end
end

expand(6) # => [[6], [5, 1], [4, 2], [4, 1, 1], [3, 3], [3, 2, 1], [3, 1, 1, 1], [2, 2, 2], [2, 2, 1, 1], [2, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1]] 
Marc-André Lafortune
  • 78,216
  • 16
  • 166
  • 166