Is there a quick way to sort "chapter numbers" in Ruby?
1.1.1
1.1.2
1.2.1
1.3.1
1.3.2
1.3.3
10.42.64
etc.?
Do I have to write an enumerator or something like that?
Is there a quick way to sort "chapter numbers" in Ruby?
1.1.1
1.1.2
1.2.1
1.3.1
1.3.2
1.3.3
10.42.64
etc.?
Do I have to write an enumerator or something like that?
In Ruby, Array
s are ordered lexicographically, so the easiest way would be to convert these into Array
s and then sort them:
chapters = %w[1.1.1 1.1.2 1.2.1 1.3.1 1.3.2 1.3.3 10.42.64]
chapters.sort_by {|chapter| chapter.split('.').map(&:to_i) }
# => ["1.1.1", "1.1.2", "1.2.1", "1.3.1", "1.3.2", "1.3.3", "10.42.64"]
Of course, the real solution would be to use objects instead of slugging around arrays of strings of numbers. After all, Ruby is an object-oriented language, not an arrays-of-strings-of-numbers-oriented language:
class ChapterNumber
include Comparable
def initialize(*nums)
self.nums = nums
end
def <=>(other)
nums <=> other.nums
end
def to_s
nums.join('.')
end
alias_method :inspect, :to_s
protected
attr_reader :nums
private
attr_writer :nums
end
chapters = [ChapterNumber.new(1, 1, 1), ChapterNumber.new(1, 1, 2),
ChapterNumber.new(1, 2, 1), ChapterNumber.new(1, 3, 1),
ChapterNumber.new(1, 3, 2), ChapterNumber.new(1, 3, 3),
ChapterNumber.new(10, 42, 64)]
chapters.sort
# => [1.1.1, 1.1.2, 1.2.1, 1.3.1, 1.3.2, 1.3.3, 10.42.64]
(l: string, r: string) => {
const left = l.split('.');
const right = r.split('.');
let count = Math.max(left.length, right.length);
let idx = 0;
while (idx < count) {
const lValue = parseInt((left[idx] || '0'));
const rValue = parseInt((right[idx] || '0'));
if (lValue === rValue) {
idx++
} else {
return lValue < rValue ? -1 : lValue > rValue ? 1 : 0;
}
}
return 0;
};