如何使用sort_by按字母顺序排序,然后按数字排序,然后按特殊字符排序



我有一个数组:

arr = ["Bar", "abc", "foo", "1", "20”, "10", "_def"]

我需要首先使用不区分大小写的字母顺序进行排序,然后按数字顺序排序,然后按特殊字符排序。

我正在尝试使用sort_by

irb(main):071:0> arr.sort_by {|s| [s[/[0-9a-z]+/], s.to_i]}
=> ["1", "10", "20", "abc", "Bar", "_def", "foo"]

输出必须是:

arr = ["abc", "Bar", "foo", "1", “10”, “20", "_def"]

从文档中:

数组以"元素"的方式进行比较;ary的第一个元素与other_ary的第一个元素进行比较,使用<=>运算符,然后是第二个元素中的每一个,依此类推。

您可以通过创建排序组来利用此行为:

arr = ["Bar", "abc", "foo", "1", "20", "10", "_def"]
arr.sort_by do |s|
case s
when /^[a-z]/i
[1, s.downcase]
when /^d/
[2, s.to_i]
else
[3, s]
end
end
#=> ["abc", "Bar", "foo", "1", "10", "20", "_def"]

第一个元素(123(定义了群的位置:字母的字符串放在第一个位置,数字字符串放在第二个位置,其余的放在第三个位置。在每个组中,元素按第二个元素排序:带有字母的字符串按其小写值排序,数字字符串按其整数值排序,其余元素按其本身排序。

您可以先创建组,然后再对组进行排序。

arr.each_with_object(Array.new(3) { Array.new }) do |word, group|
if word.match /^[A-Za-z]/
group.first
elsif word.match /^[0-9]/
group.second
else
group.third
end << word
end.flat_map{ |group| group.sort_by{ |x| x.downcase } }
#=> ["abc", "Bar", "foo", "1", "10", "20", "_def"]

需要一点基准:

require 'active_support/core_ext/array/access.rb'
require 'fruity'
ARR = ["Bar", "abc", "foo", "1", "20", "10", "_def"]
def run_demir(ary)
ary.each_with_object(Array.new(3) { Array.new }) do |word, group|
if word.match /^[A-Za-z]/
group.first
elsif word.match /^[0-9]/
group.second
else
group.third
end << word
end.flat_map{ |group| group.sort_by{ |x| x.downcase } }
end
def run_stefan(ary)
ary.sort_by do |s|
case s
when /^[a-z]/i
[1, s.downcase]
when /^d/
[2, s.to_i]
else
[3, s]
end
end
end
run_demir(ARR)  # => ["abc", "Bar", "foo", "1", "10", "20", "_def"]
run_stefan(ARR) # => ["abc", "Bar", "foo", "1", "10", "20", "_def"]
compare do
demir  { run_demir(ARR)  }
Stefan { run_stefan(ARR) }
end

这导致:

# >> Running each test 512 times. Test will take about 1 second.
# >> Stefan is faster than demir by 2x ± 0.1

最新更新