您可以使用避免使用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 operator 将数组转换为end_with? 的可接受值:
'foo'.end_with?(*['a', 'b', 'c'])
=> false
'foo'.end_with?(*['a', 'b', 'c', 'o'])
=> true
更新以澄清给出的示例
从下面的 cmets 来看,Rich_F 对这个关于 splat 运算符的答案感到非常困惑,所以我将澄清我的答案,以帮助确保没有其他人对我提供的示例感到困惑。
Ruby 中的 splat 运算符 * 会将数组的内容转换为以逗号分隔的参数列表。在将数组作为参数传递给方法时经常使用它,例如:
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
唯一的变化是添加*。通过在参数filetypes 之前添加splat 运算符*,filetypes 数组将扩展为end_with? 调用的逗号分隔参数。
这不是问题的有效解决方案,因为它需要为目录列表的每次迭代迭代一次 filetypes 数组,并且迭代目录中的所有对象而不考虑匹配,而不是使用 Dir[Dir.pwd + '/*.{flac,wv}'].each { |filename| pp filename }仅返回相关文件,并且不必为每次迭代遍历第二个数组。因此,在给出的示例中使用end_with? 效率非常低,不应在任何实际代码中使用。
例如,给定一个包含 10,000 个以 .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)
当匹配文件的数量远低于不匹配文件的数量时,差异变得更加明显。在这里,该目录有 1,000 个.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)