views:

359

answers:

8

I've started with Ruby and am finding new, shorter, elegant ways to write code everyday.

In solving Project Euler problems, I've written a lot of code like

if best_score < current_score
  best_score = current_score
end

Is there a more elegant way to write this?

+13  A: 

This can be done on a single line:

best_score = current_score if best_score < current_score
Trevor
Putting the conditionals at the end of the statement is just brilliant.
Anurag
+5  A: 

Maybe a one-liner?

best_score = current_score if best_score < current_score
Nils Riedemann
A: 

Not sure it would qualify as "more elegant", but if you don't want to rewrite the if every time ...

def max(b,c)
 if (b < c)
  c
 else
  b
 end
end

best = 10 
current = 20
best = max(best,current)
phtrivier
-1 He's not trying to swap the variables. Reread the question.
Tomas
@Tomas: `swap` is a misnomer here. `max` would be a more apt description for what the function actually *does*.
mipadi
God I hate when I miss the obvious. Thanks ;)
phtrivier
+2  A: 

This is elegant enough. It's readable and easy to maintain.

If you want shorter, you can go:

best_score = current_score if best_score < current_score

or

best_score = current_score unless best_score >= current_score

... but it's not necessarily an improvement in all cases (keep in mind readability).

marcgg
A: 

Or this way

(current_score > best_score) ? best_score = current_score : best_score
java_dude
+13  A: 
best_score = [best_score, current_score].max

see: Enumerable.max


disclaimer: although this is a little more readable (imho), it's less performant:

require 'benchmark'

best_score, current_score, n = 1000, 2000, 100_000

Benchmark.bm do |x|
  x.report { n.times do best_score = [best_score, current_score].max end }
  x.report { n.times do 
    best_score = current_score if best_score < current_score 
  end }
end

will result in (with ruby 1.8.6 (2008-08-11 patchlevel 287)):

    user     system      total        real
0.160000   0.000000   0.160000 (  0.160333)
0.030000   0.000000   0.030000 (  0.030578)
The MYYN
This is swatting a fly with a bat, no?
guns
The nice thing about this solution is that the array can contain any number of elements.
Geo
@guns, see edit ...
The MYYN
Thanks for the benchmarks. Enumerable's max method looks great, but I might have to switch to the conditionals at the end when I cross like problem 50 :)
Anurag
@The MYYN: I take my comment back. Enumerable#max is great for inline expression substitutions; it's only a little silly for the OP's original use case.
guns
A: 

It looks just fine the way you have it already. I would only change the comparison so it reads:

If current score is greater than best score

You may also create a method and call that. That's more OO to me.

 def get_best_score() 
      current_score > best_score ?
          current_score :
          best_score
 end

This is what OOP is all about isn't? Hold the object state.

best_score = get_best_score()
OscarRyz
If we're talking about elegance, best_score = get_best_score would be better. or just score = best_score
marcgg
Since you're capturing variables, why not go for a lambda instead?
Geo
I'm more like OO and less Func
OscarRyz
+1  A: 

Since I can't see it above, I lean toward this use of the ternary operator:

best_score = current_score > best_score ? current_score : best_score

and there's also this rather less frequently-encountered version:

best_score = (best_score > current_score && best_score) || current_score

...which is harder to read, but shows a (to me) slightly unexpected side-effect of short-circuiting. (See this blog post.)

Mike Woodhouse
Anurag
@Anurag - yes it should, thanks. Inadequate test cases! I'll fix it.
Mike Woodhouse