如何订购字母列表(“a”,“b”,“c”,…,“z”,“aa”,“ab”)? 字符串#sunk和在这种情况下似乎不能很好地协同工作
我的一个对象(’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
相同的规则。
我从这里的评论中发现了这一点 – 但现在我很难找到解决这个问题的好方法。 问题基本上是这样的:
"aa".succ #=> "ab" - great, that's what I want. "z""aa" #=> 1 - not so great, "z" should actually be less than "aa"
显然,这不一定是一个bug,但它使得以这种格式排序和排序letter_ids列表非常困难。 有没有人遇到这个并找到了解决方法,或者我可能会尝试的任何建议? 谢谢!
在你发布的链接的答案中有一个解决方案 – 你必须在sort_by{|i|[i.length,i]}
编写自己的<=>
irb> %w{abcz aa ab zz aaa}.shuffle.sort_by { |i| [i.length,i] } => ["a", "b", "c", "z", "aa", "ab", "zz", "aaa"]
您可以覆盖Item模型的<=>
方法,首先按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长度(即"aa"
之前的"aa"
"z"
"aa"
),然后按字典顺序进行比较。
这种问题正是为什么有些人不鼓励使用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
。