Topa_14 Topa_14 - 2 months ago 9
Ruby Question

Directory with a number of files and subdirectories: I need to move those files into each subdirectories,as per file name in Ruby

I have one directory with a number of files and subdirectories. I need to move those files into each subdirectories, depending on their naming. For instance:

Files:

Hello.doc
Hello.txt
Hello.xls
This_is_a_test.doc
This_is_a_test.txt
This_is_a_test.xls
Another_file_to_move.ppt
Another_file_to_move.indd


Subdirectories:

Folder 01 - Hello
Folder 02 - This_is_a_test
Folder 03 - Another_file_to_move


What I need is to move the three files named
Hello
into folder
Folder 01 - Hello
; the three files called
This_is_a_test
into directory
Folder 02 - This_is_a_test
and the two files named
Another_file_to_move
into directory called
Folder 03 - Another_file_to_move
. I have hundreds of files, not just these ones.

As it can be seen, the folder name contain the name of the file at the end, but at the beginning there is a
Folder
+
\s
+ a
number
+
\s
+ a
-
. This is a global pattern.

Any help?

Answer

Don't rush, try to solve your problem step by step. I would solve your problem in the following steps:

1. Separate files from subdirectories

subdirectories, files = Dir['/path/to/the/directory/*'].partition{|path| File.directory?(path)}
# TODO ...

2. Iterate over the files and retrieve the basename of each file, without extension

subdirectories, files = Dir['/path/to/the/directory/*'].partition{|path| File.directory?(path)}

files.each do |file|
  basename = File.basename(file, '.*')
  # TODO ...
end

3. Find the subdirectory that the file should go to

subdirectories, files = Dir['/path/to/the/directory/*'].partition{|path| File.directory?(path)}

files.each do |file|
  basename = File.basename(file, '.*')
  subdirectory = subdirectories.find {|d| File.basename(d) =~ /^Folder \d+ - #{Regexp.escape(basename)}$/}
  # TODO ...
end

4. Move the file into that directory

require 'fileutils'

subdirectories, files = Dir['/path/to/the/directory/*'].partition{|path| File.directory?(path)}

files.each do |file|
  basename = File.basename(file, '.*')
  subdirectory = subdirectories.find {|d| File.basename(d) =~ /^Folder \d+ - #{Regexp.escape(basename)}$/}
  FileUtils.mv(file, subdirectory + '/')
end

Done. But finding subdirectories using regexp is expensive and we don't want to do this for each file. Can you optimize it?

HINT 1: Trade memory for time.
HINT 2: Hash.

Comments