首页 > 解决方案 > 用ruby中的数字和字符对字符串数组进行排序

问题描述

我有一个给定字符串的数组

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"
]

标签: rubysorting

解决方案


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]] }

推荐阅读