Flatten Folders

I require a script that will flatten a folder overwriting any files that are duplicate filenames. I have written one myself but seems to fall over with duplicate file names. If I could also ensure that the most recent file was kept that would also be a great help.
Steve

Hi Steve,
This script was written quickly so it has little error checking or thought to it. You can try to make it more efficient. It seems to work with the little testing I did.

-- This script deletes files with duplicate names 
-- according to date modified from a chosen folder. 

set the_folder to ¬ 
 (choose folder with prompt "Choose a folder to remove duplicates:") 
set file_refs to MakeFileList(the_folder) 
set num_items to count file_refs 
if num_items > 1 then 
 tell application "Finder" 
  set file_refs to (sort file_refs by name) 
  repeat with i from 2 to num_items 
   set j to i - 1 
   set ref_i to item i of file_refs 
   set ref_j to item j of file_refs 
   set name_i to name of ref_i 
   set name_j to name of ref_j 
   if name_i is name_j then 
    set mod_date_i to modification date of ref_i 
    set mod_date_j to modification date of ref_j 
    if mod_date_i > mod_date_j then 
     delete ref_j 
    else 
     delete ref_i 
     set item i of file_refs to ref_j 
    end if 
   end if 
  end repeat 
 end tell 
end if 

on MakeFileList(the_folder) 
 set file_list to {} 
 tell application "Finder" 
  set item_list to every item of the_folder 
  repeat with i in item_list 
   if file type of i is "fold" then 
    set file_list to file_list & MakeFileList(i) of me 
   else 
    set file_list to file_list & i 
   end if 
  end repeat 
 end tell 
 return file_list 
end MakeFileList

gl, Kel.

: Hi Steve,
: This script was written quickly so it has little error checking or thought to
: it. You can try to make it more efficient. It seems to work with the
: little testing I did.
:
: – This script deletes files with duplicate names – according to date
: modified from a chosen folder. set the_folder to ¬ (choose
: folder with prompt “Choose a folder to remove duplicates:”) set
: file_refs to MakeFileList(the_folder) set num_items to count file_refs
: if num_items > 1 then tell application “Finder”
: set file_refs to (sort file_refs by name) repeat with i
: from 2 to num_items set j to i - 1 set ref_i
: to item i of file_refs set ref_j to item j of file_refs
: set name_i to name of ref_i set name_j to name
: of ref_j if name_i is name_j then set
: mod_date_i to modification date of ref_i set
: mod_date_j to modification date of ref_j if mod_date_i
: > mod_date_j then delete ref_j
: else delete ref_i
: set item i of file_refs to ref_j
: end if end if end repeat
: end tell end if on MakeFileList(the_folder) set file_list
: to {} tell application “Finder” set item_list to
: every item of the_folder repeat with i in item_list
: if file type of i is “fold” then set
: file_list to file_list & MakeFileList(i) of me else
: set file_list to file_list & i end if
: end repeat end tell return file_list end
: MakeFileList

Thanks for all this. Wiill give it a try and let you know how I get on.

Steve
: gl, Kel.

: Hi Steve,
: This script was written quickly so it has little error checking or thought to
: it. You can try to make it more efficient. It seems to work with the
: little testing I did.

Does this script take in account recursive folders, as what I am ultimately after is some code that will flatten the folder at the same time so from a group of nested folders it ends with a single folder containg all file elements with duplicates deleted.

Steve

:
: – This script deletes files with duplicate names – according to date
: modified from a chosen folder. set the_folder to ¬ (choose
: folder with prompt “Choose a folder to remove duplicates:”) set
: file_refs to MakeFileList(the_folder) set num_items to count file_refs
: if num_items > 1 then tell application “Finder”
: set file_refs to (sort file_refs by name) repeat with i
: from 2 to num_items set j to i - 1 set ref_i
: to item i of file_refs set ref_j to item j of file_refs
: set name_i to name of ref_i set name_j to name
: of ref_j if name_i is name_j then set
: mod_date_i to modification date of ref_i set
: mod_date_j to modification date of ref_j if mod_date_i
: > mod_date_j then delete ref_j
: else delete ref_i
: set item i of file_refs to ref_j
: end if end if end repeat
: end tell end if on MakeFileList(the_folder) set file_list
: to {} tell application “Finder” set item_list to
: every item of the_folder repeat with i in item_list
: if file type of i is “fold” then set
: file_list to file_list & MakeFileList(i) of me else
: set file_list to file_list & i end if
: end repeat end tell return file_list end
: MakeFileList
: gl, Kel.

Hi Steve,

Yes. You can only have duplicate names in sub-folders. However, it does not eliminate the sub-folders. I’m about to sleep now, but, a quick thought is that you can bring the file to the root level at the same time where you’re comparing 2 files and their names are not the same then you would bring file j to the root level. So you might look for the form:

if name_i is name_j then 
-- whatever went here 
else 
-- move the file to root level
end if

Then, lastly, you would have to eliminate all folders of the_folder.

Later, Kel.

Also, you have to think about the last loop. If the last two items of the list have the same names then one will be deleted and the last item in the list will be left there without being moved. If the last two items have different names then the second to last will be moved, but, the last item will still be left. So, when you exit the repeat loop, you need to move the last item in the list to the root level. Then, eliminate all the sub-folders.
Later again, Kel.

Hi Steve,

Here’s the working script according to what you wanted:

-- This script deletes files with duplicate names 
-- according to date modified from a chosen folder.

set the_folder to ¬ 
 (choose folder with prompt "Choose a folder to remove duplicates:") 
set file_refs to MakeFileList(the_folder) 
set num_items to count file_refs 
if num_items > 1 then 
 tell application "Finder" 
  set file_refs to (sort file_refs by name) 
  repeat with i from 2 to num_items 
   set j to i - 1 
   set ref_i to item i of file_refs 
   set ref_j to item j of file_refs 
   set name_i to name of ref_i 
   set name_j to name of ref_j 
   if name_i is name_j then 
    set mod_date_i to modification date of ref_i 
    set mod_date_j to modification date of ref_j 
    if mod_date_i > mod_date_j then 
     delete ref_j 
    else 
     delete ref_i 
     set item i of file_refs to ref_j 
    end if 
   else 
    move ref_j to the_folder 
   end if 
  end repeat 
  move last item of file_refs to the_folder 
  delete (every folder of the_folder) 
 end tell 
end if 

on MakeFileList(the_folder) 
 set file_list to {} 
 tell application "Finder" 
  set item_list to every item of the_folder 
  repeat with i in item_list 
   if file type of i is "fold" then 
    set file_list to file_list & MakeFileList(i) of me 
   else 
    set file_list to file_list & i 
   end if 
  end repeat 
 end tell 
 return file_list 
end MakeFileList

You might try testing it on copies of the original folder first. The list of files could be huge so increase the script app’s memory. 4 Mb worked with a list of about 200 files and I don’t know how much more it would have worked with. Note that it doesn’t take into account case of the characters of names. If you want case then you can use the statements:

considering case
-- statements where case must be considered
end considering

Lastly, try to look through it and see how you can make it better and possibly faster although it seems to work.

gl and happy scripting, Kel.

Since, we’re deleting sub-folders at the end, you don’t have to delete files here:

if mod_date_i > mod_date_j then 
 delete ref_j 
else 
 delete ref_i 
 set item i of file_refs to ref_j 
end if

So, change these lines to:

if mod_date_i < mod_date_j then 
 set item i of file_refs to ref_j 
end if

Have a good day.

Fixed some stuff. :slight_smile:

-- This script deletes files with duplicate names 
-- according to date modified from a chosen folder. 
-- Also, moves the files to the root level of the folder 
-- and deletes all sub-folders. 

set the_folder to ¬ 
 (choose folder with prompt "Choose a folder to remove duplicates:") 
set file_refs to MakeFileList(the_folder) 
set num_items to count file_refs 
tell application "Finder" 
 if num_items > 0 then 
  set file_refs to (sort file_refs by name) as list 
  if num_items > 1 then 
   repeat with i from 2 to num_items 
    set j to i - 1 
    set ref_i to item i of file_refs 
    set ref_j to item j of file_refs 
    set name_i to name of ref_i 
    set name_j to name of ref_j 
    if name_i is name_j then 
     set mod_date_i to modification date of ref_i 
     set mod_date_j to modification date of ref_j 
     if mod_date_i > mod_date_j then 
      delete ref_j 
     else 
      delete ref_i 
      set item i of file_refs to ref_j 
     end if 
    else 
     move ref_j to the_folder 
    end if 
   end repeat 
  end if 
  move last item of file_refs to the_folder 
 end if 
 set subfolder_list to every folder of the_folder 
 if subfolder_list is not {} then 
  delete (every folder of the_folder) 
 end if 
end tell 

-- returns a list of all files within the folder and sub-folders 

on MakeFileList(the_folder) 
 set file_list to {} 
 tell application "Finder" 
  set item_list to every item of the_folder 
  repeat with i in item_list 
   if file type of i is "fold" then 
    set file_list to file_list & MakeFileList(i) of me 
   else 
    set file_list to file_list & i 
   end if 
  end repeat 
 end tell 
 return file_list 
end MakeFileList

gl, Kel.