简体   繁体   中英

How could I DRY this while loop?

I need to DRY this code but I don't know how.

I tried to dry the if condition but I don't know how to put the while in this.

def sum_with_while(min, max)
  # CONSTRAINT: you should use a while..end structure
  array = (min..max).to_a
  sum = 0
  count = 0
  if min > max
    return -1
  else
    while count < array.length
      sum += array[count]
      count += 1
    end
  end

  return sum
end

Welcome to stack overflow!

Firstly, I should point out that "DRY" stands for "Don't Repeat Yourself". Since there's no repetition here, that's not really the problem with this code.

The biggest issue here is it's unrubyish. The ruby community has certain things it approves of, and certain things it avoids. That said, while loops are themselves considered bad ruby, so if you've been told to write it with a while loop, I'm guessing you're trying to get us to do your homework for you.

So I'm going to give you a couple of things to do a web search for that will help start you off:

  • ruby guard clauses - this will reduce your if-else-end into a simple if
  • ruby array pop - you can do while item = array.pop - since pop returns nil once the array is empty, you don't need a count. Again, bad ruby to do this... but maybe consider while array.any?
  • ruby implicit method return - generally we avoid commands we don't need

It's worth noting that using the techniques above, you can get the content of the method down to 7 reasonably readable lines. If you're allowed to use .inject or .sum instead of while , this whole method becomes 2 lines.

(as HP_hovercraft points out, the ternary operator reduces this down to 1 line. On production code, I'd be tempted to leave it as 2 lines for readability - but that's just personal preference)

You can put the whole thing in one line with a ternary:

def sum_with_while(min, max)
  min > max ? -1 : [*(min..max)].inject(0){|sum,x| sum + x }
end

This is one option, cleaning up your code, see comments:

def sum_with_while(range) # pass a range
  array = range.to_a
  sum, count = 0, 0 # parallel assignment
  while count < array.length
    sum += array[count]
    count += 1
  end
  sum # no need to return
end


sum_with_while(10..20)
#=> 165


More Rubyish:

 (min..max).sum 

Rule 1: Choose the right algorithm.

You wish to compute an arithmetic series . 1

def sum_with_while(min, max)
  max >= min ? (max-min+1)*(min+max)/2 : -1   
end

sum_with_while(4, 4)
  #=> 4 
sum_with_while(4, 6)
  #=> 15 
sum_with_while(101, 9999999999999)
  #=> 49999999999994999999994950

1. An arithmetic series is the sum of the elements of an arithmetic sequence. Each term of the latter is computed from the previous one by adding a fixed constant n (possibly negative). Here max-min+1 is the number of terms in the sequence and (min+max)/2 , if (min+max) is even, is the average of the values in the sequence. As (max-min+1)*(min+max) is even, this works when (min+max) is odd as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM