Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create all possible combinations with two arrays

Tags:

ruby

My problem now is to find the number in form a**b a,b < 100 that its, sum of digits is the largest, and to do so I decided to use arrays! I make two arrays a, and b like so:

a = []
b = []
(1..100).map {|n| a << n}
(1..100).map {|n| b << n}

and I also decided to make a sum_of_digits method:

class Integer
  def sum_of_digits
  self.to_s.split("").map {|p| p.to_i}.reduce(:+)
  end
end

So now I need to construct an array that contains all the combinations of a**b How could I do this? Thanks!

like image 486
Reoxy Avatar asked Jan 02 '14 18:01

Reoxy


3 Answers

You could use the Array#product method:

a = [1,2,3]
b = [4,5,6]

a.product(b)
# => [[1, 4], [1, 5], [1, 6], [2, 4], ...]

a.product(b).map { |x, y| x ** y }
# => [1, 1, 1, 16, 32, 64, 81, 243, 729]

Then, given your Integer#sum_of_digits definition:

a.product(b).map { |x, y| x ** y }.max_by(&:sum_of_digits)
# => 729

Update: to compute the maximum digital sum of the numbers (a ** b), where a, b are natural numbers less or equal to 100, I'd do like this:

Array(1..100)
  .repeated_permutation(2)
  .map { |a, b| (a ** b).sum_of_digits }
  .max
like image 60
toro2k Avatar answered Nov 22 '22 16:11

toro2k


Skip the arrays and use the repeated_permutation helper on the range to get an enumerator:

(1..100).to_a.repeated_permutation(2)

Calling to_a on the enumerator will get you an array of all permutations. However, you can operate on the enumerator directly to work more efficiently:

(1..100).to_a.repeated_permutation(2).reduce([0]) do |m,(a,b)| 
  r = (a**b).sum_of_digits
  r > m.last ? [[a,b],r] : m
end
=> [[99, 95], 972]

While you can call map and then find max. that will require actually holding all permutation results at once. Calling reduce on the enumerator will only require holding at any given time a single permutation and the result of the prior permutation.

like image 43
PinnyM Avatar answered Nov 22 '22 14:11

PinnyM


Edit: @PinnyM correctly pointed out that I should have used Array#repeated_permutation rather than Array#permutation, because the latter does not include pairs [i,i]. Rather than making the correction I've fix it slightly differently, in the interest of diversity, by replacing a.permutation(2).to_a with a.permutation(2).to_a + a.zip(a).

  a = (1..100).to_a
  (a.permutation(2).to_a + a.zip(a)).map {|i,j| (i ** j).sum_of_digits}.max
    # => 972

And the winner is:

  (a.permutation(2).to_a + a.zip(a)).map \
    {|i,j| [i, j, (i ** j).sum_of_digits]}.max_by(&:last)
    # => [99, 95, 972] (99**95).sum_of_digits # => 972

If i <= 3, rather than i <= 100, the following steps are performed:

a = (1..3).to_a # => [1,2,3]
b = a.permutation(2) # => #<Enumerator: [1, 2, 3]:permutation(2)>
c = b.to_a # => [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]] 
d = a.zip(a) # => [[1, 1], [2, 2], [3, 3]]
e = c + d # => [[1,2], [1,3], [2,1], [2,3], [3,1], [3,2], [1,1], [2,2], [3,3]] 
f = e.map {|i,j| (i ** j).sum_of_digits} # => [1, 1, 2, 8, 3, 9, 1, 4, 9]
f.max # => 9

In Ruby 2.0 you can limit the use of the method sum_of_digits to your current context (e.g., class) by replacing class Integer with refine Integer do. If you think you might want to use that method elsewhere, you could put it in a module and include the module where needed.

like image 32
Cary Swoveland Avatar answered Nov 22 '22 16:11

Cary Swoveland