defmodule sort_files_by_extension do
def sort_files do
File.ls!("./test")
|> Enum.map(fn filename ->
extname = Path.extname(filename) #=> ".jpg"
basename = Path.basename(filename, extname) #=> "IMG_XXXX"
{basename, extname, filename}
end)
|> Enum.map(&make_extension_dir/1)
|> Enum.map(&dedup/1)
|> Enum.each(&move_extension_directory/1)
defp make_extension_dir({_, "." <> extension, _} = arg) do
File.mkdir_p!("./#{extension}")
arg # just return the argument for other `Enum.map`
end
defp dedup(arg, suffix \\ 0)
defp dedup({basename, "." <> extension, filename} = arg, 0) do
if File.exists?("#{extension}/#{filename}") do
dedup(arg, 1)
else
arg
end
end
defp dedup({basename, "." <> extension = extname, filename} = arg, suffix) do
if File.exists?("#{extension}/#{basename}_#{suffix}.#{extension}") do
dedup(arg, suffix + 1)
else
{"#{basename}_#{suffix}", extname, filename}
end
end
defp move_to_extension_directory({basename, "." <> extension, filename}) do
File.rename!("./test/#{filename}", "./#{extension}/#{basename}.#{extension}")
end
end
A few suggestions:
Enum.eachis for pure side effects (e.g. pure file system operations). It’s not chainable. UseEnum.mapinstead.- You can wrap all the information in a tuple, and pattern match on it in the function parameters.
- You can trust the file system to do the right thing (e.g.
File.mkdir_p!) - Hail recursion!






















