# Find the lowest and second lowest values in an array of numbers

Trying to find way to do this with only one pass through the array, so I won't run a sort on it and take arr[0..1]. Not sure how to make it look better:

def LowestSecondLowest(arr)
lowest,second_lowest = nil,nil

arr.each do |n|

if second_lowest.nil?
second_lowest=n
elsif lowest.nil?
if n>second_lowest
lowest=second_lowest
second_lowest=n
elsif n<second_lowest
lowest=n
end
elsif n<lowest
second_lowest=lowest
lowest=n
elsif n>lowest && n<second_lowest
second_lowest=n
end
end

"#{lowest} #{second_lowest}"
end

• It often results in simpler code to start with lowest, second_lowest = VERY_LARGE_NUMBER, VERY_LARGE_NUMBER Feb 27, 2017 at 22:08
• Array#min can return the two lowest values: [3,2,1].min(2) Mar 21, 2017 at 12:10

Because Array lets you put repeated elements of same value, I believe that the two lowest elements in [1, 2, 1] are [1, 1], not [1, 2]. This is the very same behavior one would face if sorting the array and getting the two first elements. Also I believe that in [1] there is a lowest and no 2nd lowest (also, the very same behavior if sorting and getting the first two).

With this in mind, I changed your code to obey these premises (and make it a bit more readable if I may say). Take a look.

def two_lowest arr
# if arr has no elements, there is no answer
# If arr has only one element, this is the lowest
if arr.size < 2 then
return arr.first, nil
end

lowest, second_lowest = nil, nil

arr.each do |n|
if lowest.nil? or n < lowest
# if we have no lowest or we found an element lower than current lowest,
# update our lowest and 2nd lowest
second_lowest = lowest
lowest = n
elsif second_lowest.nil? or n < second_lowest
# if we have no 2nd lowest or we found an element between lowest and 2nd
# lowest, update our 2nd lowest
second_lowest = n
end
end

return lowest, second_lowest
end


If you want to test it

tests = [
[],
[1],
[1, 1],
[1 ,2],
[1, 2, 1],
[1, 2, 3],
[1, 1, 2, 3],
[3, 2, 1, 1],
]

for test in tests
puts "In #{test}:"
puts "#{two_lowest test}"
puts
end

• Thanks very much, Gabriel. I understand the logic behind your revisions. I think my sloppiness came from not considering what would get caught in previous if/elsif statements, and therefore trying to accommodate unnecessary values in subsequent if/elsif statements Feb 28, 2017 at 14:14
• Treating corner cases before main iteration/recursion is a "trick" I usually do to simplify my code. So after all ifs I can forget about corner cases and write just for the general case. I am glad I could help you, it is my first answer in CodeReview :-) Feb 28, 2017 at 17:28
• Would you mind elaborating for me what you mean? I'm still rather new to coding and general strategies like you mention here are not familiar to me. Thanks! Mar 1, 2017 at 19:36
• This strategy is called "early exit". It is discussed here. I hope it helps! Mar 1, 2017 at 22:52