Ruby有一个natural_sort_by方法吗?

我有一堆带有一堆属性的文件。 其中一个属性是文件名,这就是我想对列表进行排序的方式。 但是,列表如下所示:filename 1,filename 2,filename 10,filename 20。

ruby sort_by方法产生:

files = files.sort_by { |file| file.name } => [filename 1, filename 10, filename 2, filename 20] 

我想要一个更易读的列表,如文件名1,文件名2,文件名10,文件名20

我找到了natural_sort gem,但它似乎只能像sort方法一样工作。 我需要一些东西,我可以指定对数组进行排序的内容。

有帮助吗?

只要文件总是命名为"file #" ,你就可以做到

files.sort_by{|f| f.name.split(" ")[1].to_i }

这会拆分空间,并抓取数字进行排序。

这是另一种“自然”排序方法:

 class String def naturalized scan(/[^\d\.]+|[\d\.]+/).collect { |f| f.match(/\d+(\.\d+)?/) ? f.to_f : f } end end 

这将像"Filename 10"这样的东西转换成一个简单的数组,浮点数代替数字[ "Filename", 10.0 ]

您可以在列表中使用此选项:

 files.sort_by! { |file| file.name.to_s.naturalized } 

这具有在不可预测的位置处理任意数字的优点。 该块中的偏执.to_s调用是为了确保在排序时存在字符串而不是无意的nil

字符串自然排序的通用答案

 array.sort_by {|e| e.split(/(\d+)/).map {|a| a =~ /\d+/ ? a.to_i : a }} 

我创造了一个天然的gem 。 它可以按如下属性排序:

 # Sort an array of objects by the 'number' attribute Thing = Struct.new(:number, :name) objects = [ Thing.new('1.1', 'color'), Thing.new('1.2', 'size'), Thing.new('1.1.1', 'opacity'), Thing.new('1.1.2', 'lightness'), Thing.new('1.10', 'hardness'), Thing.new('2.1', 'weight'), Thing.new('1.3', 'shape') ] Naturally.sort_by(objects, :number) # => [#, #, #, #, #, #, #] 

它正确排序。 这里的问题是名称不适合按你想要的方式排序。 在字符串中,10在2之前,21在5之前。

如果你想让它像数字那样排序,你有两种方法:

1 – 更改所有列表,在仅包含一位数的数字前添加前导0。

2 – 按照威廉的建议,将名称变为aplit,将字符串转换为整数并按其排序。

我建议选项1,因为第二个依赖于名称的padronization。