Arrays ruby字母数字排序未按预期工作
给定以下数组:Arrays ruby字母数字排序未按预期工作,arrays,ruby,sorting,alphanumeric,Arrays,Ruby,Sorting,Alphanumeric,给定以下数组: y = %w[A1 A2 B5 B12 A6 A8 B10 B3 B4 B8] => ["A1", "A2", "B5", "B12", "A6", "A8", "B10", "B3", "B4", "B8"] 预期的排序数组为: => ["A1", "A2", "A6", "A8", "B3", "B4", "B5", "B8", "B10", "B12"] 使用以下(普通)排序,我得到: irb(main):2557:0> y.sort{|a,b| pu
y = %w[A1 A2 B5 B12 A6 A8 B10 B3 B4 B8]
=> ["A1", "A2", "B5", "B12", "A6", "A8", "B10", "B3", "B4", "B8"]
预期的排序数组为:
=> ["A1", "A2", "A6", "A8", "B3", "B4", "B5", "B8", "B10", "B12"]
使用以下(普通)排序,我得到:
irb(main):2557:0> y.sort{|a,b| puts "%s <=> %s = %s\n" % [a, b, a <=> b]; a <=> b}
A1 <=> A8 = -1
A8 <=> B8 = -1
A2 <=> A8 = -1
B5 <=> A8 = 1
B4 <=> A8 = 1
B3 <=> A8 = 1
B10 <=> A8 = 1
B12 <=> A8 = 1
A6 <=> A8 = -1
A1 <=> A2 = -1
A2 <=> A6 = -1
B12 <=> B3 = -1
B3 <=> B8 = -1
B5 <=> B3 = 1
B4 <=> B3 = 1
B10 <=> B3 = -1 # this appears to be wrong, looks like 1 is being compared, not 10.
B12 <=> B10 = 1
B5 <=> B4 = 1
B4 <=> B8 = -1
B5 <=> B8 = -1
=> ["A1", "A2", "A6", "A8", "B10", "B12", "B3", "B4", "B5", "B8"]
irb(main):2557:0>y.sort{a,b |放置“%s%s=%s\n”%[a,b,ab];ab}
A1 A8=-1
A8 B8=-1
A2 A8=-1
B5 A8=1
B4 A8=1
B3 A8=1
B10 A8=1
B12 A8=1
A6 A8=-1
A1 A2=-1
A2 A6=-1
B12 B3=-1
B3 B8=-1
B5 B3=1
B4 B3=1
B10 B3=-1#这似乎是错误的,看起来比较的是1,而不是10。
B12 B10=1
B5 B4=1
B4 B8=-1
B5 B8=-1
=>[“A1”、“A2”、“A6”、“A8”、“B10”、“B12”、“B3”、“B4”、“B5”、“B8”]
…这显然不是我想要的。我知道我可以尝试先对alpha进行拆分,然后对数值进行排序,但似乎我不应该这么做
arr = ["A1", "A2", "B5", "B12", "A6", "AB12", "A8", "B10", "B3", "B4",
"B8", "AB2"]
可能的大警告:我们现在一直在使用Ruby 1.8.7:(但即使是Ruby 2.0.0也在做同样的事情。我在这里遗漏了什么
建议?需要自然或词典排序,而不是标准的基于字符值的排序。类似于这些gems的东西将是一个起点:
人类将像“A2”这样的字符串视为“a”,后跟数字2,并对字符串部分使用字符串排序,对数字部分使用数字排序。标准的
sort()
使用字符值排序,将字符串视为一个字符序列,而不管字符是什么。对于sort()
“A10”“A2”看起来像['A','1','0']和['A','2'],因为“1”在“2”之前排序,而下面的字符不能改变顺序,“A10”因此在“A2”之前排序。对于人类来说,相同的字符串看起来像['A',10]和['A',2],在2之后进行10次排序,因此我们得到了相反的结果。可以对字符串进行操作,使基于字符值的sort()
产生预期的结果,方法是将数字部分设置为固定宽度,并在左侧补零以避免嵌入空格,使“A2”变成“A02”,使用标准sort()在“A10”之前进行排序
需要自然或词典排序,而不是标准的基于字符值的排序。类似于这些gems的东西将是一个起点:
人类将像“A2”这样的字符串视为“a”,后跟数字2,并对字符串部分使用字符串排序,对数字部分使用数字排序。标准的
sort()
使用字符值排序,将字符串视为一个字符序列,而不管字符是什么。对于sort()
“A10”“A2”看起来像['A','1','0']和['A','2'],因为“1”在“2”之前排序,而下面的字符不能改变顺序,“A10”因此在“A2”之前排序。对于人类来说,相同的字符串看起来像['A',10]和['A',2],在2之后进行10次排序,因此我们得到了相反的结果。可以对字符串进行操作,使基于字符值的sort()
产生预期的结果,方法是将数字部分设置为固定宽度,并在左侧补零以避免嵌入空格,使“A2”变成“A02”,使用标准sort()在“A10”之前进行排序
您正在对字符串进行排序。字符串是像字符串一样排序的,而不是像数字一样排序的。如果您想像数字一样排序,那么您应该对数字而不是字符串进行排序。字符串'B10'
在字典上比字符串'B3'
小,这不是Ruby独有的,甚至不是编程独有的,不是吗这就是在编程、数据库、词典、词典、电话簿等各个领域,按字典顺序对文本进行排序的方式
您应该将字符串拆分为数字和非数字分量,并将数字分量转换为数字。数组排序是字典式的,因此最终的排序将完全正确:
y.sort_by {|s| # use `sort_by` for a keyed sort, not `sort`
s.
split(/(\d+)/). # split numeric parts from non-numeric
map {|s| # the below parses numeric parts as decimals, ignores the rest
begin Integer(s, 10); rescue ArgumentError; s end }}
#=> ["A1", "A2", "A6", "A8", "B3", "B4", "B5", "B8", "B10", "B12"]
您正在对字符串进行排序。字符串是像字符串一样排序的,而不是像数字一样排序的。如果您想像数字一样排序,那么您应该对数字而不是字符串进行排序。字符串
'B10'
在词典学上比字符串'B3'
小,这不是Ruby独有的东西,甚至不是编程独有的东西,这就是为什么在编程、数据库、词典、词典、电话簿等领域,按Xicography排序一段文本几乎无处不在
您应该将字符串拆分为数字和非数字分量,并将数字分量转换为数字。数组排序是字典式的,因此最终的排序将完全正确:
y.sort_by {|s| # use `sort_by` for a keyed sort, not `sort`
s.
split(/(\d+)/). # split numeric parts from non-numeric
map {|s| # the below parses numeric parts as decimals, ignores the rest
begin Integer(s, 10); rescue ArgumentError; s end }}
#=> ["A1", "A2", "A6", "A8", "B3", "B4", "B5", "B8", "B10", "B12"]
如果您知道数字中的最大位数是多少,您也可以在比较期间在数字前面加上
0
y.sort_by { |string| string.gsub(/\d+/) { |digits| format('%02d', digits.to_i) } }
#=> ["A1", "A2", "A6", "A8", "B3", "B4", "B5", "B8", "B10", "B12"]
此处'%02d'
指定以下内容,%
表示值的格式,0
然后指定以0
s作为数字前缀,2
指定数字的总长度,d
指定您希望以小数(以10为基数)输出。您可以找到其他信息
这意味着
'A1'
将转换为'A01'
,'B8'
将变成'B08'
,'B12'
将保持'B12'
,因为它已经有两个数字。这仅在比较期间使用。如果您知道数字中的最大位数是多少,您也可以在数字前面加上前缀在比较过程中,rs与0
y.sort_by { |string| string.gsub(/\d+/) { |digits| format('%02d', digits.to_i) } }
#=> ["A1", "A2", "A6", "A8", "B3", "B4", "B5", "B8", "B10", "B12"]
此处'%02d'
指定以下内容,%
表示值的格式,0
然后指定以0
s作为数字前缀,2
指定数字的总长度,d
指定您希望以小数(以10为基数)输出。您可以找到其他信息
这意味着'A1'
将转换为'A01'
,'B8'
将变成'B08'
,'B12'
将保持'B12'
max_len = arr.max_by(&:size).size
#=> 4
arr.sort_by { |s| "%s%s%d" % [s[/\D+/], " "*(max_len-s.size), s[/\d+/].to_i] }
#=> ["A1", "A2", "A6", "A8", "AB2", "AB12", "B3", "B4", "B5", "B8",
# "B10", "B12"]
arr.each { |s| puts "%s-> \"%s\"" %
["\"#{s}\"".ljust(7), s[/\D+/] + " "*(max_len-s.size) + s[/\d+/]] }
"A1" -> "A 1"
"A2" -> "A 2"
"B5" -> "B 5"
"B12" -> "B 12"
"A6" -> "A 6"
"AB12" -> "AB12"
"A8" -> "A 8"
"B10" -> "B 10"
"B3" -> "B 3"
"B4" -> "B 4"
"B8," -> "B 8"
"AB2" -> "AB 2"