HiveBrain v1.2.0
Get Started
← Back to all entries
patternrubyMinor

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

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
thevaluesarraylowestnumberssecondfindand

Problem

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 nlowest && n<second_lowest
      second_lowest=n
    end       
  end

  "#{lowest} #{second_lowest}"
end

Solution

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

Code Snippets

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
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

Context

StackExchange Code Review Q#156474, answer score: 3

Revisions (0)

No revisions yet.