I have a list of files with a bunch of attributes. One of the attributes is the file name which is how I would like to sort the list. However, the list goes something like this: filename 1, filename 2, filename 10, filename 20.
我有一个包含一系列属性的文件列表。其中一个属性是文件名,这是我想对列表进行排序的方式。但是,这个列表是这样的:文件名1,文件名2,文件名10,文件名20。
The ruby sort_by method produces this:
ruby sort_by方法产生如下:
files = files.sort_by { |file| file.name }
=> [filename 1, filename 10, filename 2, filename 20]
I would like a more human readable list like filename 1, filename 2, filename 10, filename 20
我想要一个更人类可读的列表,如文件名1,文件名2,文件名10,文件名20
I found the natural_sort gem but it seems to only work like the sort method. I need something where I can specify what to sort the array by.
我找到了natural_sort gem,但它似乎只像sort方法一样工作。我需要一些东西来指定数组的排序方式。
Any help?
任何帮助吗?
5 个解决方案
#1
7
As long as files are always named "file #"
, you could do
只要文件总是命名为“file #”,您就可以这样做
files.sort_by{|f| f.name.split(" ")[1].to_i }
文件。f sort_by { | | f.name.split(" ")[1]。to_i }
This splits on the space, and grabs the number to do the sorting.
这将在空间上进行分割,并获取进行排序的编号。
#2
24
Here's another take on a "natural" sort method:
下面是另一种“自然”排序方法:
class String
def naturalized
scan(/[^\d\.]+|[\d\.]+/).collect { |f| f.match(/\d+(\.\d+)?/) ? f.to_f : f }
end
end
This converts something like "Filename 10"
into a simple array with floats in place of numbers [ "Filename", 10.0 ]
这将“Filename 10”之类的内容转换为一个简单的数组,其中浮点数代替数字["Filename", 10.0]
You can use this on your list:
你可以在你的列表中使用这个:
files.sort_by! { |file| file.name.to_s.naturalized }
This has the advantage of working on arbitrary numbers in unpredictable positions. The paranoid .to_s
call in that block is to ensure that there is a string and not an inadvertent nil
when sorting.
这具有在不可预测的位置上处理任意数字的优点。该块中的偏执的.to_s调用是为了确保在排序时有一个字符串而不是无意的nil。
#3
13
generic answer for strings natural sort
字符串自然排序的一般答案
array.sort_by {|e| e.split(/(\d+)/).map {|a| a =~ /\d+/ ? a.to_i : a }}
#4
6
I've created a natural sort gem. It can sort by an attribute like this:
我创造了一颗天然的宝石。它可以通过如下属性进行排序:
# 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)
# => [#<struct Thing number="1.1", name="color">,
#<struct Thing number="1.1.1", name="opacity">,
#<struct Thing number="1.1.2", name="lightness">,
#<struct Thing number="1.2", name="size">,
#<struct Thing number="1.3", name="shape">,
#<struct Thing number="1.10", name="hardness">,
#<struct Thing number="2.1", name="weight">]
#5
-3
It is sorting correctly. The problem here is that the names aren't good to sort the way you want. In means of string, 10 comes before 2 and 21 comes before 5.
这是正确的排序。这里的问题是这些名称不适合按照您想要的方式进行排序。用字符串表示,10在2之前,21在5之前。
If you want it to sort it like it was numbers, you have 2 approaches:
如果你想把它排序成数字,你有两种方法:
1 - Change all your listings to add a leading 0 before numbers with just one digit.
1 -改变你所有的清单,在数字前加上一个0,只有一个数字。
2 - Do as William suggested, aplit the name, transform the string to integer and sort by it.
2 -按照William的建议,命名,将字符串转换为整型并对其进行排序。
I would recommend option 1 since the second rely on the padronization of the names.
我建议选择1,因为第二个选择依赖于名称的padronization。
#1
7
As long as files are always named "file #"
, you could do
只要文件总是命名为“file #”,您就可以这样做
files.sort_by{|f| f.name.split(" ")[1].to_i }
文件。f sort_by { | | f.name.split(" ")[1]。to_i }
This splits on the space, and grabs the number to do the sorting.
这将在空间上进行分割,并获取进行排序的编号。
#2
24
Here's another take on a "natural" sort method:
下面是另一种“自然”排序方法:
class String
def naturalized
scan(/[^\d\.]+|[\d\.]+/).collect { |f| f.match(/\d+(\.\d+)?/) ? f.to_f : f }
end
end
This converts something like "Filename 10"
into a simple array with floats in place of numbers [ "Filename", 10.0 ]
这将“Filename 10”之类的内容转换为一个简单的数组,其中浮点数代替数字["Filename", 10.0]
You can use this on your list:
你可以在你的列表中使用这个:
files.sort_by! { |file| file.name.to_s.naturalized }
This has the advantage of working on arbitrary numbers in unpredictable positions. The paranoid .to_s
call in that block is to ensure that there is a string and not an inadvertent nil
when sorting.
这具有在不可预测的位置上处理任意数字的优点。该块中的偏执的.to_s调用是为了确保在排序时有一个字符串而不是无意的nil。
#3
13
generic answer for strings natural sort
字符串自然排序的一般答案
array.sort_by {|e| e.split(/(\d+)/).map {|a| a =~ /\d+/ ? a.to_i : a }}
#4
6
I've created a natural sort gem. It can sort by an attribute like this:
我创造了一颗天然的宝石。它可以通过如下属性进行排序:
# 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)
# => [#<struct Thing number="1.1", name="color">,
#<struct Thing number="1.1.1", name="opacity">,
#<struct Thing number="1.1.2", name="lightness">,
#<struct Thing number="1.2", name="size">,
#<struct Thing number="1.3", name="shape">,
#<struct Thing number="1.10", name="hardness">,
#<struct Thing number="2.1", name="weight">]
#5
-3
It is sorting correctly. The problem here is that the names aren't good to sort the way you want. In means of string, 10 comes before 2 and 21 comes before 5.
这是正确的排序。这里的问题是这些名称不适合按照您想要的方式进行排序。用字符串表示,10在2之前,21在5之前。
If you want it to sort it like it was numbers, you have 2 approaches:
如果你想把它排序成数字,你有两种方法:
1 - Change all your listings to add a leading 0 before numbers with just one digit.
1 -改变你所有的清单,在数字前加上一个0,只有一个数字。
2 - Do as William suggested, aplit the name, transform the string to integer and sort by it.
2 -按照William的建议,命名,将字符串转换为整型并对其进行排序。
I would recommend option 1 since the second rely on the padronization of the names.
我建议选择1,因为第二个选择依赖于名称的padronization。