Ответ 1
Пока файлы всегда называются "file #"
, вы можете сделать
files.sort_by{|f| f.name.split(" ")[1].to_i }
Это разделяется на пробел и захватывает номер для сортировки.
У меня есть список файлов с кучей атрибутов. Одним из атрибутов является имя файла, в котором я хотел бы отсортировать список. Однако список выглядит примерно так: 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, но, похоже, работает только как метод сортировки. Мне нужно что-то, где я могу указать, для чего сортировать массив.
Любая помощь?
Пока файлы всегда называются "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 }}
Я создал натуральный жемчуг. Он может сортироваться по атрибуту, подобному этому:
# 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">]
Сортировка выполняется правильно. Проблема здесь в том, что имена не очень хороши для сортировки так, как вы хотите. В виде строки, 10 приходит до 2 и 21 до 5.
Если вы хотите, чтобы он сортировал его так, как будто это были числа, у вас есть 2 подхода:
1 - Измените все свои списки, чтобы добавить число 0 перед номерами всего с одной цифрой.
2 - Сделайте, как предложил Уильям, добавьте имя, преобразуйте строку в целое и отсортируйте по ней.
Я бы порекомендовал вариант 1, поскольку второй полагается на прокрутку имен.