Skip to main content
2 of 5
added 164 characters in body
asterix314
  • 1.3k
  • 9
  • 19

The “Suffix trie” provides a good way to think about the problem. However, the following implementation uses a more straightforward approach under the same principle. Given a list of directory name, we will produce the mapping {"dir" -> "label" ...}, where directories with distinctive last n components are labeled by their last n components concatenated, for smallest n.

We define labelRules[dirs, n] to give the list of rules {"dir" -> "label" ...} where each label consists of at least n components: we pick out from the directory list those distinguishable by last n components, then join them with labelRules[rest, n+1]. The recursion stops at labelRules[{}, _] which is just {}. The final result is given by labelRules[dirs, 1].

labelRules[{}, _Integer] := {}
labelRules[dirs : {__String}, n_Integer: 1] := Module[{s},
    s = Join @@
            Select[
                GatherBy[dirs, FileNameTake[#, {-n}] &],
                Length[#] == 1 &];
    Map[# -> StringReplace[
            FileNameTake[#, -n],
            $PathnameSeparator -> "."] &, s]
    ~Join~
    labelRules[Complement[dirs, s], n + 1]]


labelRules[{"common/a/b/c", "common/b/c", "common/x/y/z"}]

(*Out: {"common/x/y/z" -> "z", "common/a/b/c" -> "a.b.c", "common/b/c" -> "common.b.c"} *)

Note that the above does not always give the shortest possible label. For example it will give {"x/a/c" -> "a.c", "x/y/c" -> "y.c"} instead of e.g. {"x/a/c" -> "c", "x/y/c" -> "y.c"}.

asterix314
  • 1.3k
  • 9
  • 19