2016-08-18 24 views
0

鉴于以下阵列工作红宝石字母排序并不如预期

=> ["A1", "A2", "A6", "A8", "B3", "B4", "B5", "B8", "B10", "B12"] 

使用以下(香草)排序,我得到:

irb(main):2557:0> y.sort{|a,b| puts "%s <=> %s = %s\n" % [a, b, a <=> b]; a <=> b} 
A1 <=> A8 = -1 
A8 <=> B8 = -1 
A2 <=> A8 = -1 
B5 <=> A8 = 1 
B4 <=> A8 = 1 
B3 <=> A8 = 1 
B10 <=> A8 = 1 
B12 <=> A8 = 1 
A6 <=> A8 = -1 
A1 <=> A2 = -1 
A2 <=> A6 = -1 
B12 <=> B3 = -1 
B3 <=> B8 = -1 
B5 <=> B3 = 1 
B4 <=> B3 = 1 
B10 <=> B3 = -1 # this appears to be wrong, looks like 1 is being compared, not 10. 
B12 <=> B10 = 1 
B5 <=> B4 = 1 
B4 <=> B8 = -1 
B5 <=> B8 = -1 
=> ["A1", "A2", "A6", "A8", "B10", "B12", "B3", "B4", "B5", "B8"] 

......这显然不是我所希望的。我知道我可以尝试首先在alpha上分割,然后对数值进行排序,但似乎我不应该那样做。

可能重要的提醒:我们使用Ruby卡住1.8.7现在:(但即使红宝石2.0.0做同样的事情缺少什么我在这里

建议

+3

您的第一个预感是正确的;因为这些是字符串,它们将按照字典顺序排列。如果你想把这个数字作为排序的一个元素,你需要将这个数字与数字分开,并在分类时使用它自己的意愿。 – Makoto

+2

我很好奇你为什么认为*字符串*“B12”会在*字符串*“B2”之前排序。这不是Ruby如何对字符串进行排序的方式,这就是* everything *字符串的排序方式。 – meagar

+0

你想'y.sort_by {| s | [s [0],s [1..-1] .to_i]}#=> [“A1”,“A2”,“A6”,“A8”,“B3”,“B4”,“B5” “B8”,“B10”,“B12”]。关于Ruby如何对数组进行排序,请参见[Array#<=>](http://ruby-doc.org/core-2.3.0/Array.html#method-i-3C-3D-3E)。 –

回答

1

您正在排序字符串。字符串按字符串排序,不像数字。如果你想排序像数字,那么你应该排序数字,而不是字符串。字符串'B10'在字典顺序上比字符串'B3'小,这不是Ruby独有的,甚至不是编程所特有的东西,这就是在编程,数据库,词典,字典,电话簿等中按字母顺序排列一段文本的方法。等等。

您应该将您的字符串拆分为它们的数字和非数字分量,并将数字分量转换为数字。阵列排序是词典编排,所以这将最终排序完全正确:

y.sort_by {|s| # use `sort_by` for a keyed sort, not `sort` 
    s. 
    split(/(\d+)/). # split numeric parts from non-numeric 
    map {|s| # the below parses numeric parts as decimals, ignores the rest 
     begin Integer(s, 10); rescue ArgumentError; s end }} 
#=> ["A1", "A2", "A6", "A8", "B3", "B4", "B5", "B8", "B10", "B12"] 
-1

?A?自然或词典排序,而不是一个标准的基于字符值的排序,就像这些宝石将是一个起点:https://github.com/dogweather/naturally,https://github.com/johnnyshields/naturalsort

人类视为“A”字符串为“A”后跟数字2,然后使用字符串排序对字符串部分和数字排序进行排序RT。标准sort()使用字符值排序将字符串视为字符序列,而不管字符是什么。因此,对于sort()“A10”和“A2”看起来像['A','1','0']和['A','2'],因为'1'在'2'之前排序,并且以下字符可以因此不会改变该订单“A10”因此在“A2”之前排序。对于人类来说,相同的字符串看起来像[“A”,10]和[“A”,2],10之后有10种,所以我们得到相反的结果。可以通过操纵字符串使基于字符值的sort()产生预期的结果,方法是将左侧的数字部分固定宽度和零填充以避免嵌入空格,从而使“A2”变成“A02”使用标准sort()在“A10”之前排序。

+0

这实际上解决了这个问题,但它并不能解释为什么这种排序不能用于开箱即用。非常有趣,但。 – Jim

+1

数字值的排序方式与其字符串表示的字符排序不同。字符值排序不适用于例如。 “A10”和“A2”,因为'1'的字符值小于'2',这使得“A10”在“A2”之前排序。 OTOH将自然类型解释为“A2”等同于“A02”或[“A”,2](我们将其视为“A”,然后是数字2)。 –

+1

注意:以上就是为什么在数据文件中经常在固定宽度的固定小数位零填充字段中看到右对齐的数字,以便字符排序与数字排序的结果匹配。 –