Write a function
lucky_sevens?(numbers)
, which takes in an array of integers and returns true if any three consecutive elements sum to 7.lucky_sevens?([2,1,5,1,0]) == true # => 1 + 5 + 1 == 7 lucky_sevens?([0,-2,1,8]) == true # => -2 + 1 + 8 == 7 lucky_sevens?([7,7,7,7]) == false lucky_sevens?([3,4,3,4]) == false
Make sure your code correctly checks for edge cases (i.e. the first and last elements of the array).
While my code does seem to work (I did some test cases), I know it can be improved. There's no reason to have double puts
and return statements. I'm also wondering if there are general improvements to the syntax itself that can make it much more readable.
def lucky_sevens?(numbers)
i = 0
while i < numbers.length - 2
if numbers[i] + numbers[i + 1] + numbers[i + 2] == 7
puts true
return true
end
i+=1
end
puts false
return false
end
2 Answers 2
Your code, is way too imperative to be idiomatic Ruby.
The only reasonable improvement is re-writing it from scratch:
def lucky_sevens?(numbers)
groups_of_three(numbers)
.any? {|group| group.inject(:+) == 7}
end
Knowing that inject(:+)
means sum
, this reads like English. Implementing groups_of_three
is left as an exercise for the reader.
-
\$\begingroup\$ Could the downvoter explain why? I am always happy to receive constructive criticism :) \$\endgroup\$Caridorc– Caridorc2015年10月26日 14:16:40 +00:00Commented Oct 26, 2015 at 14:16
Looping using an index is not idiomatic in Ruby. Looping using #each
and Enumerable
methods based on #each
are much more common. This is a perfect opportunity to use Enumerable#each_cons(3)
.
def lucky_sevens?(numbers)
numbers.each_cons(3) { |group| return true if group.reduce(:+) == 7 }
false
end
The problem doesn't ask you to print anything, so don't.
-
\$\begingroup\$ Writing
groups_of_three
was left as an exercise for the reader :o, showing the right built-in right away in my opinion seems to encourage laziness... \$\endgroup\$Caridorc– Caridorc2015年10月20日 21:49:32 +00:00Commented Oct 20, 2015 at 21:49 -
1\$\begingroup\$ Don't use my
return true if ...
. @Caridorc'sany?
is much better. \$\endgroup\$200_success– 200_success2015年10月20日 21:51:44 +00:00Commented Oct 20, 2015 at 21:51 -
\$\begingroup\$ @200_success, In fairness, your version is more performant as it will return immediately upon finding a success, whereas the
any?
version requires all groups of three to be calculated, even if, say, the first 3 numbers in the array summed to 7 \$\endgroup\$Jonah– Jonah2015年10月21日 17:40:59 +00:00Commented Oct 21, 2015 at 17:40 -
\$\begingroup\$ Also, depending on your context, the
false
return value at the end may be unnecessary, sinceeach_cons
returnsnil
, which will evaluate to false. \$\endgroup\$Jonah– Jonah2015年10月21日 17:44:58 +00:00Commented Oct 21, 2015 at 17:44 -
1\$\begingroup\$ @Jonah
Enumeration#any?
does short-circuit. You can see that[3,2,1,0].each_cons(3).any? { |group| 1 / group.min }
succeeds, while[2,1,0].each_cons(3).any? { |group| 1 / group.min }
crashes. \$\endgroup\$200_success– 200_success2015年10月21日 17:46:50 +00:00Commented Oct 21, 2015 at 17:46