【问题标题】:Version sort (with alphas, betas, etc.) in rubyruby 中的版本排序(带有 alpha、beta 等)
【发布时间】:2016-01-22 05:59:43
【问题描述】:

如何在 Ruby 中对版本列表进行排序?我见过有关自然排序的东西,但这是超越了那一步。

输入是一堆这样的字符串:

input = ['10.0.0b12', '10.0.0b3', '10.0.0a2', '9.0.10', '9.0.3']

我几乎可以用naturally gem 做到这一点:

require 'naturally'
Naturally.sort(input)
=> ["9.0.3", "9.0.10", "10.0.0a2", "10.0.0b12", "10.0.0b3"]    

问题:10.0.0b3 排在 10.0.0b12 之后; 10.0.0b3 应该是第一个。

有人有办法吗?其他语言也很有帮助!

【问题讨论】:

  • 这些是非常非典型的版本字符串。您不太可能找到现成的解决方案;你应该自己写。
  • 我将其更改为使用语义版本控制。这更典型。
  • @MusashiAharon 这不是语义版本控制。为此,您希望 b12 b3 等前面有 -
  • 是的。使用连字符,自然排序可以很好地工作,但是这种几乎是语义的系统仍然很常见。

标签: ruby sorting natural-sort version-sort


【解决方案1】:

在您使用 NuGet 并希望通过 NuGet 特有的 Ruby 代码自己的版本控制方案进行解析、比较或排序的特定情况下,现在有:

https://rubygems.org/gems/nuget_versions

我专门创建它来解决这个问题。 NuGet 的版本号有点奇怪,它们是 SemVer 的超集,也允许使用 4 个组件而不是 3 个。

【讨论】:

    【解决方案2】:

    Ruby 附带 Gem 类,它知道版本:

    ar = ['10.0.0b12', '10.0.0b3', '10.0.0a2', '9.0.10', '9.0.3']
    
    p ar.sort_by { |v| Gem::Version.new(v) }
    # => ["9.0.3", "9.0.10", "10.0.0a2", "10.0.0b3", "10.0.0b12"]
    

    【讨论】:

    • 不错。对于它的价值 - 看起来这仅按字母顺序处理“alpha”和“beta”。也就是说,['9.0.10rc2', '9.0.10', '9.0.10rc1', '9.0.10a', '9.0.10test'] 产生["9.0.10a", "9.0.10rc1", "9.0.10rc2", "9.0.10test", "9.0.10"]。应该足够了,因为“alpha / beta / pre-release / rc / release”无论如何都会按字母顺序排列,但如果您的数据偏离太远,可能会很奇怪。
    • 它的工作原理非常有趣:github.com/rubygems/rubygems/blob/…
    【解决方案3】:

    如果您将此解释为“按每个数字段排序”,那么您将处理上面的示例输入:

    input.map{ |ver| ver.split(%r{[^\d]+}).map(&:to_i) }.zip(input).sort.map(&:last)
    => ["9_0", "9_1", "10_0b3", "10_0b12"]
    

    也就是说,

    • 对于每个值,例如10_0b3
    • 拆分任意长度的非数字字符,例如["10","0","3"]
    • 将每个数字段转换为整数,例如[10,0,3]
    • 使用原始输入压缩,产生[[[10, 0, 12], "10_0b12"], [[10, 0, 3], "10_0b3"], [[9, 0], "9_0"], [[9, 1], "9_1"]]
    • 排序,凭借[10,0,3] < [10,0,12]
    • 获取每个元素的最后一个值,即原始输入值对应于每个已处理的可排序值

    现在,这仍然是非常自定义的——不会处理像“9_0a”和“9_0b”这样简单的版本号,两者都会显示为 [9,0]——所以你可能需要调整它更进一步,但希望这能让你走上一条可行的道路。

    编辑: 上面的示例输入已更改,因此我更改了正则表达式以确保数字匹配是贪婪的,并且它仍然成立:

    irb(main):018:0> input = ['10.0.0b12', '10.0.0b3', '9.0.10', '9.0.3']
    => ["10.0.0b12", "10.0.0b3", "9.0.10", "9.0.3"]
    irb(main):025:0> input.map{ |ver| ver.split(%r{[^\d]+}).map(&:to_i) }.zip(input).sort.map(&:last)
    => ["9.0.3", "9.0.10", "10.0.0b3", "10.0.0b12"]
    

    【讨论】:

    • 这确实有帮助,但 beta 并不是唯一可能的后缀。我们也可以有像 '10.0.0a2' 这样的 alpha 版本或像 '10.0.0rc1' 这样的候选版本。如果这些与其他并排排列,则排序中断。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多