我有一个包含给定字符串的数组
array = [
"1mo-30-super",
"1mo-40-classic",
"1mo-30-classic",
"1mo-110-super",
"1mo-20-extra",
"6mo-21-super",
"6mo-11-super",
"12mo-21-classic",
"12mo-21-super"
]
如何对数组进行排序,使其按数字顺序,然后按字母顺序排列,以便数组显示如下:
array = [
"1mo-20-extra",
"1mo-30-classic",
"1mo-30-super",
"1mo-40-classic",
"1mo-110-super",
"6mo-11-super",
"6mo-21-super",
"12mo-21-classic",
"12mo-21-super"
]
答案 0 :(得分:1)
您正在寻找一种“自然”的排序方式,其中将数字子字符串与数字进行比较,而将非数字部分与字符串进行比较。足够方便的是,Ruby中的数组会逐个元素地进行比较,并且您的格式相当规则,因此您可以通过#sort_by
调用和一些麻烦的操作将"12mo-21-classic"
转换为[12, 'mo-', 21, '-classic']
。例如:
# This is a bit complicated so we'll give the logic a name.
natural_parts = ->(s) { s.match(/(\d+)(\D+)(\d+)(\D+)/).to_a.drop(1).map.with_index { |e, i| i.even?? e.to_i : e } }
array.sort_by(&natural_parts)
答案 1 :(得分:1)
array.sort_by { |s| [s.to_i, s[/(?<=-)\d+/].to_i, s.gsub(/\A.+-/,'')] }
#=> ["1mo-20-extra", "1mo-30-classic", "1mo-30-super", "1mo-40-classic", "1mo-110-super",
# "6mo-11-super", "6mo-21-super", "12mo-21-classic", "12mo-21-super"]
对数组进行排序时,方法Arrays#<=>用于对数组进行排序。有关如何执行此操作的说明,请参见文档的第三段。
用于排序的数组如下。
array.each do |s|
puts "%-15s -> [%2d, %3d, %s]" % [s, s.to_i, s[/(?<=-)\d+/].to_i, s.gsub(/\A.+-/,'')]
end
1mo-30-super -> [ 1, 30, super]
1mo-40-classic -> [ 1, 40, classic]
1mo-30-classic -> [ 1, 30, classic]
1mo-110-super -> [ 1, 110, super]
1mo-20-extra -> [ 1, 20, extra]
6mo-21-super -> [ 6, 21, super]
6mo-11-super -> [ 6, 11, super]
12mo-21-classic -> [12, 21, classic]
12mo-21-super -> [12, 21, super]
(?<=-)
是正向查找。它要求匹配必须紧跟连字符。 /\A.+-/
匹配字符串的开头,后跟一个或多个字符,后跟一个连字符。由于正则表达式默认为 greedy ,因此它会在第二个连字符处得出匹配结果。
请注意,没有必要使用正则表达式:
array.sort_by { |s| [s.to_i, s[s.index('-')+1..-1].to_i, s[s.rindex('-')+1..-1]] }
答案 2 :(得分:0)
您可以链接多个#sort
方法调用,每个方法调用均按字符串的不同部分排序(从优先级最低的字符串开始):
array.sort { |a,b| a.match(/-(.*)$/)[1] <=> b.match(/-(.*)-/)[1] } # sort by last element ('classic', 'super')
.sort { |a,b| a.match(/-(\d+)-/)[1].to_i <=> b.match(/-(\d+)-/)[1].to_i } # sort by the number between dashes
.sort { |a,b| a.to_i <=> b.to_i } # sort by the initial number
=> ["1mo-20-extra",
"1mo-30-classic",
"1mo-30-super",
"1mo-40-classic",
"1mo-110-super",
"6mo-11-super",
"6mo-21-super",
"12mo-21-super",
"12mo-21-classic"]