首先,您的my_array
是JavaScript/JSON格式,因此我假设您实际上有以下内容:
my_array = [
{"id" => "some-server-1", "foo" => "bar"},
{"id" => "some-server-2", "foo" => "bat"},
{"id" => "some-server-10", "foo" => "baz"}
]
然后,您只需要sort_by
'id'
值的数字后缀:
my_array.sort_by { |e| e['id'].sub(/^some-server-/, '').to_i }
my_array.sort_by { |e| e['id'].scan(/\D+|\d+/).map { |x| x =~ /\d/ ? x.to_i : x } }
'id'
值分成数字和非数字部分,将数字部分转换为整数,然后使用数组<=>
运算符(逐个组件比较)比较混合的字符串/整数数组;只要数字和非数字组件始终匹配即可。这种方法可以处理以下情况:my_array = [
{"id" => "some-server-1", "foo" => "bar"},
{"id" => "xxx-10", "foo" => "baz"}
]
但不包括这个:
my_array = [
{"id" => "11-pancakes-23", "foo" => "baz"},
{"id" => "some-server-1", "foo" => "bar"}
]
如果您需要处理这种情况,则需要手动逐个比较数组的每个条目,并根据您所拥有的信息调整比较。您仍然可以通过类似以下代码(经过不太充分的测试)来获得 sort_by
Schwartzian Transform 的一些优势:
class NaturalCmp
include Comparable
attr_accessor :chunks
def initialize(s)
@chunks = s.scan(/\D+|\d+/).map { |x| x =~ /\d/ ? x.to_i : x }
end
def <=>(other)
i = 0
@chunks.inject(0) do |cmp, e|
oe = other.chunks[i]
i += 1
if(cmp == 0)
cmp = e.class == oe.class \
? e <=> oe \
: e.to_s <=> oe.to_s
end
cmp
end
end
end
my_array.sort_by { |e| NaturalCmp.new(e['id']) }
sort_by
变得难以理解。然后我们使用与之前相同的扫描方式将字符串分成片段,并手动实现数组<=>
比较器。如果我们有两个相同类的东西,那么我们让该类的<=>
处理它,否则我们强制将两个组件转换为字符串并进行比较。我们只关心第一个非0结果。@mu 给出了对我的情况来说更为充分的答案,但我也找到了介绍任意比较的语法:
def compare_ids(a,b)
# Whatever code you want here
# Return -1, 0, or 1
end
sorted_array = my_array.sort { |a,b| compare_ids(a["id"],b["id"] }
我认为如果你要按照id
字段排序,可以尝试这样做:
my_array.sort { |a,b| a["id"].to_i <=> b["id"].to_i }