开发者

(Ruby) how to return a -1 specifically for a specific comparison

开发者 https://www.devze.com 2022-12-08 15:30 出处:网络
let\'s say when I\'m comparing values in ruby, i have a value in mind that no matter what I want, using sort on that value and anything else returns a -1 (so this value is default sorted as smaller th

let's say when I'm comparing values in ruby, i have a value in mind that no matter what I want, using sort on that value and anything else returns a -1 (so this value is default sorted as smaller than everything).

for example, let's say i want '100' to sort smaller 100% of the time against 99. so that if i'm sorting values in an array, and a comparison comes up between 100 and 99, 100 is sorted smaller (ie, -1 is returned). but, i want all the other cases to be normal (98 is smaller than 99, 50 is bigger than 30, etc)

edit: okay this is what i want

if i hav开发者_运维技巧e an x and a y, i do not want to use

x <=> y

i want to use (in pseudocode and hand-wavy-ness)

x > y

which means, this x is always greater than this y


Why don't you instead use a dictionary to keep values associated with their relative value? In this case, the string abc can be mapped to -1, and then just make sure no other values map to values equal to or less than -1.

Edit: If you're only concerned with one particular value breaking the norm, then this solution is not for you.


Easier to handle the specialness outside of the sort!

module Enumerable
  def sort_excluding(*vals)
    special,rest = partition {|x| vals.include?(x)}
    rest.sort + special
  end
end


One way to do it would be to implement a derivative class for your custom comparisons (http://www.ruby-doc.org/core/classes/Comparable.html)

Here's some sample code (and tests) for you:

class StrA < String
 include Comparable
 attr :str
 def <=>(anOther)
  if (str == "abc" && anOther.str == "abc")
   0
  elsif (str == "abc")
   -1
  elsif (anOther.str == "abc")
   1
  else
   str <=> anOther.str
  end
 end

 def initialize(str)
  @str = str
 end

 def inspect
  @str
 end
end

And the tests:

a = StrA.new("Z")
b = StrA.new("B")
c = StrA.new("abc")
d = StrA.new("")

a > b # 1
a > c # 1
c > a # -1
d > c # 1
c > d # -1
c < d # 1
c > d # -1

[a, b, c, d].sort! # [ "Z", "B", "", "abc"]


I think what you want is:

[30, 50, 4, 0, 100, -22, 99].sort_by {|a| [a == 100 ? -1 : 0, a ]}.reverse

which gives:

99
50
30
 4
 0
-22
100

Hope I understood the question!


Array#sort or Enumerable#sort(I don't know what you are trying to sort) can take an obtional block. If the block is given, the block is used for comparison instead of <=>

For example this code will sort reversed:

foo.sort { |a,b| b <=> a }

In your case you need to call #sort something like the following:

foo.sort do |a,b|
  if [a,b].sort == [99,100]
    b-a # returns 1 or -1 so that 99 > 100
  else
    a <=> b
  end
end

I am not entirely sure about the way you are trying to sort, but this should enable you to use sort in the manner you need. More inforamtion about Array#sort, and any other method can be found on your linux(and possible other OS's) via ri like this: ri Array#sort.


You could override the sort method for the object like so:

class Fixnum
  alias old_sort <=>

  def <=>(object)
    if (self == 100 or object == 100)
      return -1
    else
      return self.old_sort object
    end
  end
end

puts (101 <=> 100)

Edit 1: Above is a fully working example.

Edit 2: As stated by johannes in the comments, you really shouldn't implement this exact code. This is merely a simple example of how to override your sorting method to do domain-specific logic. Also, updated the code to reflect johannes' other comment about comparing with both object and self.

0

精彩评论

暂无评论...
验证码 换一张
取 消