2013-07-28 5 views
0

У меня есть несколько сотен изображений в ведро S3, которое я пишу в массив и хочу, чтобы они сортировались и отображались в алфавитном порядке. Изображения начинаются с той же схемесортировать рубиновый массив по номерам

#1 <some name>.jpg 
#2 <some name>.jpg 
... 
#10 <some name>.jpg 
#11 <some name>.jpg 
... 

после использования

@images.each do |image| 
@image[i] = image.url_for(:read).to_s 
    i = i + 1 
end 

@image.sort 

однако, массив @image сортируется таким образом:

<s3 bucket URL>/#1 <some name>.jpg 
<s3 bucket URL>/#10 <some name>.jpg 
<s3 bucket URL>/#11 <some name>.jpg 
... 
<s3 bucket URL>/#2 <some name>.jpg 
<s3 bucket URL>/#20 <some name>.jpg 
<s3 bucket URL>/#21 <some name>.jpg 
... 

Это мое понимание того, что " алфавит ", и поэтому сортировка должна сортировать # 1, # 2, # 3 и т. д., но это, похоже, не так. Очевидно, что я хочу это сортируется таким образом:

<s3 bucket URL>/#1 <some name>.jpg 
<s3 bucket URL>/#2 <some name>.jpg 
<s3 bucket URL>/#3 <some name>.jpg 
... 
<s3 bucket URL>/#10 <some name>.jpg 
<s3 bucket URL>/#11 <some name>.jpg 
<s3 bucket URL>/#12 <some name>.jpg 
... 

Как я могу достичь этого с помощью алгоритма сортировки в этом случае? Спасибо за любую помощь.

ответ

2

Это мое понимание того, что "алфавит" и, следовательно, сортировка должен сортировать # 1, # 2, # 3 и т.д.

Это предложение не имеет никакого смысла, но в алфавите программирования программирования «1» идет до «2», и когда Ruby сравнивает строки, он сравнивает символ строк по символу, пока не найдет разницу. Поэтому, когда Ruby сравнивает «11» и «2», он начинается с сравнения первых символов, что означает, что он сравнивает «1» и «2». Поскольку символы различны, они не будут сравнивать больше символов; и поскольку «1» предшествует «2», строка «11» идет перед строкой «2».

fnames = [ 
    "#1 <some name>.jpg", 
    "#2 <some name>.jpg", 
    "#10 <some name>.jpg", 
    "#11 <some name>.jpg", 
] 


results = fnames.sort_by do |fname| 
    match_data = fname.match(/#(\d+)/) 
    match_data[1].to_i 
end 

p results 

--output:-- 
["#1 <some name>.jpg", 
"#2 <some name>.jpg", 
"#10 <some name>.jpg", 
"#11 <some name>.jpg"] 

И если вы в один лайнеры:

results = fnames.sort_by {|fname| fname[/#(\d+)/, 1].to_i } 

Если может быть имена файлов с одинаковыми номерами, то вам нужно сделать немного больше работы:

fnames = [ 
    "<s3 bucket URL>/#1 <some name>.jpg", 
    "<s3 bucket URL>/#10 <some name>.jpg", 
    "<s3 bucket URL>/#11 xyz.jpg", 
    "<s3 bucket URL>/#11 abc.jpg", 
    "<s3 bucket URL>/#2 <some name>.jpg", 
    "<s3 bucket URL>/#20 <some name>.jpg", 
    "<s3 bucket URL>/#21 <some name>.jpg", 
] 

results = fnames.sort_by do |fname| 
    [ 
    fname[/#(\d+)/, 1].to_i, 
    $' #The rest of the string after the match 
    ] 
end 


p results 

--output:-- 
["<s3 bucket URL>/#1 <some name>.jpg", 
"<s3 bucket URL>/#2 <some name>.jpg", 
"<s3 bucket URL>/#10 <some name>.jpg", 
"<s3 bucket URL>/#11 abc.jpg", 
"<s3 bucket URL>/#11 xyz.jpg", 
"<s3 bucket URL>/#20 <some name>.jpg", 
"<s3 bucket URL>/#21 <some name>.jpg"] 

Рубиновые сорта массивы аналогично строкам: он сравнивает первые элементы в массивах, и если они одинаковы, то он сравнивает второй элемент и т. д., пока не найдет разницу. Блок sort_by() сообщает Ruby сделать вид, что каждое имя файла фактически представляет собой массив из двух элементов.

+0

Не работает, к сожалению, массив по-прежнему сортируется # 1, # 10, # 11 .... # 2, # 21, ... вот мой код: \t 'images = s3.buckets ['mybucket «].объекты \t \t я = 0 \t fnames = Array.new \t \t images.each сделать | имя_файла | \t fnames [я] = fname.url_for (: чтение) .to_s \t я = я + 1 конец @results = fnames.sort_by сделать | имя_файла | [ имя_файла [/ # (\ d +) /, 1] .to_i, $»#The остаток строки после матча ] end' – DonMB

+0

@MartinBraun, Вы писали имена файлов, которые вы хотите отсортировать. Мой код сортирует эти имена файлов. Он работает так, как вы просили, - посмотрите результаты. Код, который вы используете для создания этих имен файлов, не имеет значения. – 7stud

+0

Я беру это отсюда, спасибо за вашу помощь! – DonMB

1
@images.sort_by{ |filename| filename[1..-1].to_i } 
+0

благодарит за ваш ответ! Предположим, вы имеете в виду @image (единственное число), так как это массив, который я хочу сортировать. использование вашего кода не помогает - оно по-прежнему сортируется одинаково. – DonMB

+0

ok, '@ image.sort_by {| filename | filename [(n + 1) ..- 1] .to_i} ', где n - длина URL-адреса ведомого s3 до и// – bgates

+0

@bgates, вы не понимаете проблему. Сортировка строк не приводит к тому же результату, что и номера сортировки. Попробуйте отсортировать строки «1», «2», «10», «11». Оператор хочет, чтобы отсортированный ордер был «1», «2», «10», «11». – 7stud

Смежные вопросы