Pick a chunk of items and distribute them in folders of a maximum size (eg, create folders to burn in 700MB CDs).
OS version: OS X
(*
knapfake 1.0
Somebody asked at bbs.applescript.net for a script which would take a bunch of files, then divide them in folders of a maximum size (useful to burn CDs, etc.). I was also looking for such tool, so I tried to write my own. The user mentioned "knapsack". I'm not sure this is related to the knapsack problem, and absolutelly sure this wouldn't be a nice implementation of such algorithm, so I called this one "knapfake".
As I understand it, the perfect algorithm would check any file against any file, creating the perfect combination to fit the maximum allowed size in different containers. "knapfake" does not work so, and most probably someone with a strong mathematical background should create SUCH script. Meanwhile, you can use this one, which:
a) Creates a list of sizes and names of folders/files (any item within "inputFolder")
b) Sorts such list in decreasing order
c) Attempts to fit each item within the first "virtual folder" of a maximum size
d) If it does exceed the maximum size, it attempts the same operation in the second "virtual folder", if it does exist. Otherwise, it creates a new folder and places the item within such "new virtual folder"
e) When all items are virtually distributed, they are moved to sub-folders within "outputFolder"
f) If any item has a size greater than the maximum allowed one, it is placed in a "badItems" list --> implement yourself the actions to be executed with such list
You must CONFIGURE the value "maxMB" (by default 690 -MB-)
You must define manually or programatically both "inputFolder" (the folder containing lots of items to be sub-divided into folders of maxMB size) and "outputFolder" (the folder where the new sub-folders will be created, and items moved within)
Actually, the script will duplicate the items to the sub-folders. If you like this script, you can ALSO configure it to MOVE the items to the sub-folders, instead of duplicating them. Search this code for "YOHOO!" and follow the instructions.
Enjoy!
Pescados Software - 19, october, 2004
*)
set maxMB to 690
set maxbytes to maxMB * (1024 ^ 2)
set inputFolder to (choose folder with prompt "Choose the folder where items to be sub-divided are located currently")
set outputFolder to (choose folder with prompt "Choose the folder where I should locate the items in different folders of max-sixe " & maxMB & " MB")
tell application "Finder" to ¬
{size, name} of items of inputFolder
set mixedList to sortLists from (mixLists(result's item 1, result's item 2)) --> I'm not sure "sortLists" is relevant in this algorithm (???)
set folders to {{}} --> a list with an "empty folder"
set excludedItems to {} --> items shifted from mixedList
set badItems to {} --> items whose size is higher than "maxbytes"
repeat with i from (count mixedList) to 1 by -1
if i is not in excludedItems and i is not in badItems then --> process this item
set itemSize to mixedList's item i's item 1
if itemSize > maxbytes then
set badItems's end to i
else --> try to add item to current "folder"
set itemWasAddedToAnExistingFolder to false
repeat with x from 1 to count folders --> folders's item x is {{size,name},{size,name},...}, Try to add this item to an existing folder
set folderSum to sumFolder(folders's item x)
if (itemSize + folderSum) < maxbytes then --> add item to this "folder"
set end of folders's item x to mixedList's item i
set itemWasAddedToAnExistingFolder to true
exit repeat
end if
end repeat
if not itemWasAddedToAnExistingFolder then
set end of folders to {mixedList's item i} --> add to a new "folder"
end if
set end of excludedItems to i --> items is now inside a "folder", so exclude it from "mixedList"
end if
end if
end repeat
--> distribute stuff
repeat with i from 1 to count folders --> "folders" is now a list of {{{size, name}, {size, name}}, {{size, name}, {size, name}}}
set currentFolder to folders's item i --> {{size, name}, {size, name}}
--> create a folder with a dummy sequential name, where we will place "files" in this "folder"
set newFolder to ((outputFolder as text) & "dummy" & i)
do shell script "mkdir -p " & quoted form of POSIX path of newFolder
repeat with singleFile in currentFolder
set filepath to alias ((inputFolder as text) & item 2 of singleFile)
--> YOHOO! if this script works fine, substitute in the following line "duplicate" with "move"
tell application "Finder" to duplicate filepath to alias newFolder replacing yes
end repeat
end repeat
beep 2
to sumFolder(l) --> l is a list as {{size,name},{size,name}}
set sum to 0
repeat with z in l
set sum to sum + (z's item 1)
end repeat
sum
end sumFolder
to mixLists(a, b)
script foo
property x : a
property y : b
property nl : {}
end script
repeat with i from 1 to count foo's x
set foo's nl's end to {foo's x's item i, foo's y's item i}
end repeat
foo's nl
end mixLists
to sortLists from rList --> credits to Kai Edwards
if rList's length < 2 then return rList
set {l, h, {m, s}} to {{}, {}, rList's {item 1, rest}}
repeat with r in s
if m's item 1 > r's item 1 then
set l's end to r's contents
else
set h's end to r's contents
end if
end repeat
if l's length > 1 then set l to sortLists from l
if h's length > 1 then set h to sortLists from h
l & {m} & h
end sortLists