Ruby String end_with?массив - PullRequest
       2

Ruby String end_with?массив

0 голосов
/ 24 октября 2018

Я ищу способ определить, заканчивается ли имя файла суффиксом внутри массива.

filetypes = %w(.flac .wv)
Dir.open(Dir.pwd).each do |filename|
  q = "." + filename.split('.').last.to_s
  pp filename if filetypes.include?(q)
end

Я думаю, что должен быть какой-то встроенный итератор, который пересекает массив квалификаторов.Я что-то здесь упускаю?

filetypes = %w(.flac .wv)
Dir.open(Dir.pwd).each do |filename|
  pp filename if filename.end_with?(filetypes)
end

Это не работает.Документы говорят это:

end_with?([suffixes]+) → true or false

Таким образом, он предполагает, что массив может быть пройден, но он не работает для меня.Как я могу передать массив в end_with??

Ответы [ 2 ]

0 голосов
/ 25 октября 2018

Вам просто не хватает оператора splat (*):

filetypes = %w(.flac .wv)

Dir.open(Dir.pwd).each do |filename|
  pp(filename) if filename.end_with?(*filetypes)
end
0 голосов
/ 25 октября 2018

Вы можете сделать это с помощью простой однострочной строки, которая позволяет не использовать end_with?:

Dir[Dir.pwd + '/*.{flac,wv}'].each { |filename| pp filename }

. На ваш вопрос о том, какие значения принимаются end_with?, ответ заключается в том, что он принимает запятую-ограниченный список значений, например:

'foo'.end_with?('a', 'b', 'c')
=> false
'foo'.end_with?('a', 'b', 'c', 'o')
=> true

Пример документации end_with?([suffixes]+) → true or false можно прочитать как "end_with? принимает один или несколько суффиксов, разделенных запятыми, которые будут обрабатываться массивом какпринимающего объекта, и если строка заканчивается каким-либо из суффиксов, тогда возвращается true, иначе возвращается false. "

Вы также можете использовать оператор splat для преобразования массива вдопустимое значение для end_with?:

'foo'.end_with?(*['a', 'b', 'c'])
=> false
'foo'.end_with?(*['a', 'b', 'c', 'o'])
=> true

Обновление для пояснения приведенных примеров

Судя по комментариям ниже, Rich_F был крайне смущен этим ответом оОператор splat, поэтому я поясню свой ответ, чтобы никто не запутался в приведенном мной примере.

Оператор splat * в Ruby преобразует содержимое массива в запятуюсписок аргументов.Он часто используется при передаче массива в качестве аргумента методу, например:

array = ['a', 'b', 'c']
'foo'.end_with?(*array)

Это "разбивает" массив в список аргументов, разделенных запятыми, и функционально эквивалентно:

'foo'.end_with?(*['a', 'b', 'c'])

Аналогично, он функционально эквивалентен:

'foo'.end_with?('a', 'b', 'c')

Аналогично, он функционально эквивалентен:

array = %w(a b c)
'foo'.end_with?(*array)

Аналогично, он функционально эквивалентен:

'foo'.end_with?(*%w(a b c))

Аналогично, это функционально эквивалентно:

filetypes = %w(.flac .wv)
filename.end_with?(*filetypes)

Учитывая это знание о том, как оператор splat влияет на массивы, и примеры передачи массивов в качестве аргументов в методы, можно сделать вывод, чтоданный пример кода в вопросе может быть изменен следующим образом:

filetypes = %w(.flac .wv)
Dir.open(Dir.pwd).each do |filename|
  pp filename if filename.end_with?(*filetypes)
end

Единственное изменение - добавить *.При добавлении оператора splat * перед аргументом filetypes массив filetypes будет расширен как аргументы с разделителями-запятыми для вызова end_with?.

Это неэффективное решение дляпроблема состоит в том, что для каждой итерации списка каталогов требуется итерация по массиву filetypes один раз, а для всех объектов в каталоге - независимо от совпадения, в отличие от использования Dir[Dir.pwd + '/*.{flac,wv}'].each { |filename| pp filename }, который возвращает только соответствующие файлы и не требует итерациичерез второй массив для каждой итерации.Таким образом, использование end_with? в данном примере крайне неэффективно и не должно использоваться ни в одном реальном коде.

Например, если задан каталог с 10000 файлов, оканчивающихся на .flac:

require 'benchmark'

dir = Dir[Dir.pwd + '/*.{flac,vw}']; nil
10.times { puts Benchmark.measure { 10000.times { dir.each { |filename| nil } } } }
  4.271809   0.001728   4.273537 (  4.274684)
  4.279765   0.002286   4.282051 (  4.283524)
  4.334877   0.004689   4.339566 (  4.343982)
  4.269334   0.001593   4.270927 (  4.272033)
  4.256148   0.001545   4.257693 (  4.258734)
  4.261371   0.001733   4.263104 (  4.264229)
  4.254568   0.001085   4.255653 (  4.256379)
  4.259886   0.001245   4.261131 (  4.261711)
  4.258024   0.001964   4.259988 (  4.261133)
  4.236385   0.001142   4.237527 (  4.238184)

По сравнению с исходным примером в вопросе, который более чем в два раза медленнее:

require 'benchmark'

dir = Dir[Dir.pwd + '/*']; nil
filetypes = %w(flac vw); nil
10.times { puts Benchmark.measure { 10000.times { dir.each { |filename| nil if filename.end_with?(*filetypes) } } } }
   9.509041   0.003634   9.512675 (  9.514197)
   9.484041   0.003079   9.487120 (  9.488686)
   9.508674   0.002872   9.511546 (  9.512768)
   9.508382   0.002809   9.511191 (  9.512343)
   9.762489   0.011043   9.773532 (  9.783415)
   9.607308   0.005655   9.612963 (  9.616716)
   9.962166   0.009848   9.972014 (  9.978026)
   9.621152   0.005883   9.627035 (  9.631075)
  10.811991   0.010787  10.822778 ( 10.831729)
  10.461568   0.013571  10.475139 ( 10.487688)

Разница становится намного более заметной, когда количество совпадающих файлов намного меньше числа несоответствующие файлы.Здесь каталог содержит 1000 .flac файлов и 9 000 .txt файлов:

require 'benchmark'

dir = Dir[Dir.pwd + '/*.{flac,vw}']; nil
10.times { puts Benchmark.measure { 10000.times { dir.each { |filename| nil } } } }
  0.384366   0.000210   0.384576 (  0.384669)
  0.384336   0.000186   0.384522 (  0.384717)
  0.386674   0.000178   0.386852 (  0.386947)
  0.383575   0.000075   0.383650 (  0.383671)
  0.382555   0.000090   0.382645 (  0.382692)
  0.384618   0.000048   0.384666 (  0.384677)
  0.384687   0.000199   0.384886 (  0.384976)
  0.386517   0.000193   0.386710 (  0.386842)
  0.386167   0.000132   0.386299 (  0.386388)
  0.390683   0.000093   0.390776 (  0.390817)

По сравнению с исходным примером с использованием оператора splat, который в 36 раз медленнее :

require 'benchmark'

dir = Dir[Dir.pwd + '/*']; nil
filetypes = %w(flac vw); nil
10.times { puts Benchmark.measure { 10000.times { dir.each { |filename| nil if filename.end_with?(*filetypes) } } } }
  11.182205   0.014303  11.196508 ( 11.210042)
  11.154286   0.011573  11.165859 ( 11.178611)
  11.081012   0.009853  11.090865 ( 11.098028)
  11.084294   0.009361  11.093655 ( 11.101870)
  10.990442   0.007118  10.997560 ( 11.002036)
  11.044119   0.009284  11.053403 ( 11.058608)
  11.072604   0.009114  11.081718 ( 11.087941)
  11.127151   0.009354  11.136505 ( 11.143270)
  11.172101   0.012262  11.184363 ( 11.195138)
  11.126791   0.010767  11.137558 ( 11.145617)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...