String/Range comparison problem

本小妞迷上赌 提交于 2019-12-07 23:27:19

问题


This make sense for things like :

irb(main):001:0> ["b", "aa", "d", "dd"].sort
=> ["aa", "b", "d", "dd"]

But doesn't for :

irb(main):002:0> ("B".."AA").each{ |x| print "#{x}," }
=> "B".."AA"

should produce : B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,=> "B".."AA" but "B" > "AA" => true

Unlike "B".."BA" ("B" > "BA" => false) :

irb(main):003:0> ("B".."BA").each{ |x| print "#{x}," }
B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AS,AT,AU,AV,AW,AX,AY,AZ,BA,=> "B".."BA"

Any advice to make "b".."aa" work as expected in ruby ?

I use

  • irb 0.9.5(05/04/13) ruby 1.8.7
  • (2009-06-12 patchlevel 174) [i486-linux]
  • Linux 2.6.31-19-generic #56-Ubuntu SMP Thu Jan 28 01:26:53 UTC 2010 i686 GNU/Linux

回答1:


The best way to do this is to subclass String and redefine the comparison operator to meet your needs. Then use your new class to make the range.

class MyString < String
  def initialize str=""
    super str
  end

  def <=>(other)
    length_cmp = self.length <=> other.length
    return length_cmp unless length_cmp == 0
    super other
  end
end

Now you can ensure that a column appears before another.

"b" < "aa" #=> false
MyString.new("b") < MyString.new("aa") #=> true

N.B.: Only the string on the left side of any comparison operator needs to be of class MyString:

MyString.new("b") < "aa" #=> true
"aa" > MyString.new("b") #=> false



回答2:


It looks like Ruby is using succ, but first it checks for end>=start, and since that is false here, it doesn't even try.

Admittedly String#succ is a weird beast here: a string's successor isn't always greater than the string, using its own comparison methods. So I'm not sure if this is technically a bug or not. It does look pretty confusing if you don't know this undocumented check, though.

Then again, judging by some of the other answers here, it looks like it does work as you expect in some versions of Ruby, so maybe it was fixed in 1.9?




回答3:


It is true that in class String, <=> and String#succ are not completely harmonized


I suppose it would be nice if for each a, b where b eventually is produced from a.succ.succ..., it was also true that a <=> b returned -1. One reason this would be nice is that it is in fact precisely <=> and succ that are used to implement ranges in the first place. Consequently, as you have noted, a Ruby String range where .succ would eventually complete the expansion doesn't work because a <=> test contradicts it and terminates the loop.

So yes, the ordering, at least for String, that is defined by <=> doesn't match the #succ method ordering. This is one reason that some developers avoid using succ.




回答4:


Any advice to make "b".."aa" work as expected in ruby ?

This DOESN'T work in ruby 1.8.7 (2009-06-12 patchlevel 174) nor in ruby 1.9.1p376 (2009-12-07 revision 26041) [i486-linux]


"b".."ba" does work...

irb(main):001:0> ("b".."ba").each {|x| print "#{x} "} b c d e f g h i j k l m n o p q r s t u v w x y z aa ab ac ad ae af ag ah ai aj ak al am an ao ap aq ar as at au av aw ax ay az ba => "b".."ba"




回答5:


This was reported as a bug in Ruby here. The results depend on which version of Ruby you are running. There is a difference between versions 1.8.6 and 1.9.1.



来源:https://stackoverflow.com/questions/2267810/string-range-comparison-problem

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!