I have an array of extensions and an array of file names:
exts = ['.zip', '.tgz', '.sql']
files = ['file1.txt', 'file2.doc', 'file2.tgz', 'file3.sql', 'file6.foo', 'file4.zip']
I want to filter the file names by one or more matching extensions. In this case, the result would be:
["file1.zip", "file2.tgz", "file3.sql", "file4.zip"]
I know I can do this with a nested loop:
exts.each_with_object([]) do |ext, arr|
entries.each do |entry|
arr << entry if entry.include?(ext)
end
end
This feels ugly to me. With select, I can avoid the feeling of nested loops:
entries.select { |entry| exts.each { |ext| entry.include?(ext) } }
This works and feels better. Is there still a more elegant way that I'm missing?
CodePudding user response:
I would use Enumerable#grep
with a regexp like this:
exts = ['.zip', '.tgz', '.sql']
files = ['file1.txt', 'file2.doc', 'file2.tgz', 'file3.sql', 'file6.foo', 'file4.zip']
files.grep(/#{Regexp.union(exts)}$/)
#=> ["file2.tgz", "file3.sql", "file4.zip"]
I use Regexp.union
instead of a simple exts.join('|')
because exts
include dots (.
) which have a special meaning in regular expressions. Regexp.union
escapes those dots automatically.
CodePudding user response:
Thinking about it a bit further, I realized I could make the select
better if I changed the logic slightly:
entries.select{ |entry| exts.include?(entry) }
As far as I can tell, this is as clean as I can get.