If they are in this format, you could add all the strings to an in-memory database.
Then, with maybe a maximum of 30 passes, something like this:
{pseudocode… dont know if you are using API1 or 2…}
dim totalrows as integer = (number of rows in the original list)
dim leftpart as string = "/"
dim shortestpath as string
dim leftchars as integer = 1
dim selectedrows as integer
selectedrows = totalrows
shortestpath = {some SQL to get min(thestring)}
//now we have either some random value nothing like the rest,
//or the shortest shared value
//work through the letters until we lose a row..
//this wont take more than 30 passes at a guess
while selectedrows = totalrows
leftpart = left(shortestpath,leftchars)
selectedrows = select count(1) where thevalue like leftpart //use parameterised
leftchars = leftchars+1
wend
//by this point, the last select got less than {total rows}, so we are not sharing
//any longer
//the shared value is all but the last character of leftpart
If we compare from the left, we realize they are identical until this point:
/Users/gijs/Documents/S
/Users/gijs/Documents/M
So I think the algorithm is really simple:
Function CommonAncestor( f1 as folderItem, f2 as folderItem) as folderItem
dim p1 as string = f1.nativePath
dim p2 as string = f2.nativePath
dim n1 as integer = p1.length
dim n2 as integer = p2.length
dim i1 as integer = 1 // string.middle is one-based
dim i2 as integer = 1
dim commonPath as string = ""
while true
if i1 > n1 then
exit while
end if
if i2 > n2 then
exit while
end if
dim c1 as string = p1.middle(i1,1)
dim c2 as string = p2.middle(i2,1)
if c1 <> c2 then
exit while
end if
commonPath = commonPath + c1
wend
if c1 <> "" then
return new folderItem(commonPath, folderItem.pathTypeNative)
else
return nil
end if
(I wrote this from memory, may have some syntax errors, but you should be able to figure it out from this outline…)