我的一个对象('item')有一个ID('letter_id')格式为“a”,“b”,...,“aa”,“ab”等。要生成它我我在像这样的实例方法中使用ruby的String#succ
:
def set_letter_id
last = parent.items.all(:order => "letter_id ASC").last
if last.nil?
self.letter_id = 'a'
else
self.letter_id = last.letter_id.succ
end
end
现在这很有效,直到第28封信。第27个将正确生成“ aa ”,但last
的值将始终返回带有' z '的letter_id的项目,因为返回的商品不遵循与String#succ
相同的规则。
我是通过评论over here发现的 - 但现在我很难找到解决这个问题的好办法。问题基本上是这样的:
"aa".succ #=> "ab" - great, that's what I want.
"z"<=>"aa" #=> 1 - not so great, "z" should actually be less than "aa"
显然,这不一定是一个bug,但它使得以这种格式排序和排序letter_id列表非常困难。有没有人遇到这个并找到了解决方法,或者我可能会尝试的任何建议?谢谢!
答案 0 :(得分:4)
您发布的链接的答案中有一个解决方案 - 您必须在<=>
sort_by{|i|[i.length,i]}
irb> %w{a b c z aa ab zz aaa}.shuffle.sort_by { |i| [i.length,i] }
=> ["a", "b", "c", "z", "aa", "ab", "zz", "aaa"]
答案 1 :(得分:2)
您可以覆盖项目模型的<=>
方法,首先按ID长度进行比较,然后按字母数字进行比较。
这样的事情:
class Item < ActiveRecord::Base
# stuff
def <=>(other)
len_comp = self.letter_id.length <=> other.letter_id.length
return len_comp if len_comp != 0
self.letter_id <=> other.letter_id
end
end
这样您首先要比较较短的ID长度(即"z"
之前的"aa"
),然后按字典顺序进行比较。
答案 2 :(得分:1)
这类问题正是为什么有些人不鼓励使用String#succ.
与Range
,Object#to_a
以及其他人发生冲突。
无论如何,你可能知道这一点,但这样的事情可能会有所帮助......
>> t
=> ["x", "y", "z", "aa", "ab", "ac", "ad", "ae", "af", "ag"]
>> t.shuffle.sort_by { |e| "%3s" % [e] }
=> ["x", "y", "z", "aa", "ab", "ac", "ad", "ae", "af", "ag"]
你甚至可以用这种方式重新规范化并省去sort_by
。