Andrew Kim
Andrew Kim

Reputation: 3335

iterate array combination method with .any method

Is there anyway to iterate through different combinations of arrays?

I'm writing a program that returns true if the largest number in an array can be the sum of any of the members of the array.

This is my code: (forgive me, i learned how to program 2 weeks ago for the first time)

def ArrayAdditionI(arr)
arr=arr.sort
largest=arr.pop
n=arr.length
  for i in 1..n
    if arr.combination(i).to_a.any? {|array| array.inject(:+)==largest}
      return true
    else
      return false
    end
  end
end

i tested it for a = [1,2,3,4] and it returned false even though clearly, 3+1 = 4. When I change the above code from arr.combination(i) to arr.combination(2) its returns true. So I'm guessing it has something to do with the combination method not being able to be looped. Any suggestions?

Upvotes: 1

Views: 287

Answers (1)

Cary Swoveland
Cary Swoveland

Reputation: 110735

You have return false in the wrong place. As it is, false is returned is there is no combination of one element (i.e., one element other than the one you've removed after sorting) that sums (i.e., is equal to) largest. Rather you want to return false only if no combination of any size sums to largest. This is what you need:

def max_match?(arr)
  arr=arr.sort
  largest=arr.pop
  n=arr.length
  for i in 1..n
    return true if arr.combination(i).any? {|array|
      array.inject(:+)==largest}
  end
  false
end

arr = [1,4,7,3,5,2,13]
max_match?(arr) #=> true
arr = [1,3,4,7,59]
max_match?(arr) #=> false

A few notes:

  • lower case letters and optional underscores are used for names of methods. You can also put a question (?) or explanation (!) mark at the end. Here a question mark seems appropriate.
  • to_a is not needed. Enumerable methods (e.g., any?) can have Enumerators as receivers.
  • sorting is expensive and unnecessary. Instead, just get the max value and remove it from the array. (Aside: you didn't say what happens if the maximum value appears more than once. See the code below and the last sentence.)
  • you don't need n=arr.length. for i in 1..arr.length is enough, except...
  • for ... is rarely used. Rubyists tend to use each instead, or one of the many methods from the Enumerable (mix-in) module (all of which invoke each).
  • you don't need return false because Ruby returns the value of the last statement evaluated, which is false if the method does not return true earlier.

Here's a more Ruby-like way to do that:

def max_match?(arr)
  mx = arr.max
  whats_left = arr - [mx]
  (1..whats_left.size).any? {|n| whats_left.combination(n).any? {|c|
    c.reduce(:+) == mx }}
end

arr = [1,4,7,3,5,2,13]
max_match?(arr) #=> true
arr = [1,3,4,7,59]
max_match?(arr) #=> false

If you wish this to return true when arr contains more than one value equal to mx, insert the following after mx = arr.max:

return true if arr.count(mx) > 1

Upvotes: 3

Related Questions