"自然"在Ruby中对哈希数组进行排序

Ben*_*ynn 3 ruby natural-sort

对于散列哈希数组自然排序有可行的答案,但是同时进行这两种操作的最佳方法是什么?

my_array = [ {"id":"some-server-1","foo":"bar"},{"id":"some-server-2","foo":"bat"},{"id":"some-server-10","foo":"baz"} ]
Run Code Online (Sandbox Code Playgroud)

我想对"id"进行排序,以便最终的排序是:

some-server-1
some-server-2
some-server-10
Run Code Online (Sandbox Code Playgroud)

我觉得必须有一个聪明有效的方法来做到这一点,虽然我个人不需要打破任何速度记录,只会排序几百项.我可以在sort_by中实现比较功能吗?

mu *_*ort 5

首先,你my_array是JavaScript/JSON,所以我假设你真的有这个:

my_array = [
    {"id" => "some-server-1",  "foo" => "bar"},
    {"id" => "some-server-2",  "foo" => "bat"},
    {"id" => "some-server-10", "foo" => "baz"}
]
Run Code Online (Sandbox Code Playgroud)

然后你只需要值sort_by的数字后缀'id':

my_array.sort_by { |e| e['id'].sub(/^some-server-/, '').to_i }
Run Code Online (Sandbox Code Playgroud)

如果"some-server-"前缀并不总是"some-server-"那么你可以尝试这样的事情:

my_array.sort_by { |e| e['id'].scan(/\D+|\d+/).map { |x| x =~ /\d/ ? x.to_i : x } }
Run Code Online (Sandbox Code Playgroud)

这会将'id'值拆分为数字和非数字片段,将数字片段转换为整数,然后使用Array <=>运算符(比较组件)比较混合字符串/整数数组; 只要数字和非数字组件始终匹配,这将起作用.这种方法可以解决这个问题

my_array = [
    {"id" => "some-server-1", "foo" => "bar"},
    {"id" => "xxx-10",        "foo" => "baz"}
]
Run Code Online (Sandbox Code Playgroud)

但不是这个:

my_array = [
    {"id" => "11-pancakes-23", "foo" => "baz"},
    {"id" => "some-server-1",  "foo" => "bar"}
]
Run Code Online (Sandbox Code Playgroud)

如果您需要处理这最后一种情况,那么您需要手动逐个比较数组,并根据您拥有的内容调整比较.您仍然可以使用类似的东西获得sort_by Schwartzian 变换的一些优点(不是经过良好测试的代码):

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']) }
Run Code Online (Sandbox Code Playgroud)

这里的基本思想是将比较噪声推向另一个类,以防止sort_by变形变得难以理解.然后我们使用与以前相同的扫描将字符串分成碎片并<=>手动实现数组比较器.如果我们有两个相同类的东西,那么我们让该类<=>处理它,否则我们强制将两个组件都串起来并比较它们.我们只关心第一个非0结果.