views:

780

answers:

2

My apologies if this has been answered before or is obvious...did some searching here and on the Goog and couldn't find an answer.

I'm looking to sort an array of Providers by price and whether they are a preferred_provider? (true or false)

For instance in array p of Providers...

p1.price == 1, p1.preferred_provider? == false
p2.price == 2, p2.preferred_provider? == true
p2.price == 3, p3.preferred_provider? == true

I would like to p.sort_by and get:

[p2 p3 p1]

IAW

p.sort_by {|x| x.preferred_provider?, x.price }

does not work and gets...

undefined method `<=>' for false:FalseClass

Any suggestions on better ways to approach this problem?

+2  A: 

You could define a <=> on the Provider class to do what you want, and then sort using the Array.sort method (rather than Enumerable.sort_by). Here's a definition of <=> that I whipped up:

class Provider
  def <=>(other)
    if preferred_provider?
      if other.preferred_provider?
        @price <=> other.price
      else
        1
      end
    else
      if other.preferred_provider?
        -1
      else
        @price <=> other.price
      end
    end
  end
end

Then, if you have your array p, you could just do p_sorted = p.sort.

(Note that I haven't tested this code, so there may be a few errors, but I think it serves to demonstrate the idea.)

mipadi
This would work but the other solution was more appropriate for my problem for reasons I didn't state in the original question. Thanks ...much appreciated.
Kevin Dewalt
+1  A: 

Most languages provide sort functions that accept comparators for this sort of thing. In Ruby, this is just array.sort:

p.sort {|a, b| if (a.preferred_provider? == b.preferred_provider?
               then a.price <=> b.price
               elsif a.preferred_provider?
                    1
               else -1
       }
David Winslow
This logic doesn't return the correct order, but it put me on the right path using a.preferred_provider? == b.preferred_provider? and reversing 1 and -1.thanks
Kevin Dewalt
Oops, of course you'd want to use == there (fixed now). To elaborate a bit, the closure should return a positive number if a comes after b, a negative number if a comes before b, and 0 if they are equal for sorting purposes. That way, an easy implementation for sorting numeric values is {|a,b| a - b}.
David Winslow