# -*- coding: utf-8 -*-
require 'pp'
# 簡単のため、フルパスのみを扱う。
paths = %w[
/full/path/to/somewhere
/full/path/to/anywhere
/full/path/to/nowhere
/full/path/to
]
# 単位に分割する。
parts_list = paths.map {|path| path.split('/')}
pp parts_list
# => [["", "full", "path", "to", "somewhere"],
# ["", "full", "path", "to", "anywhere"],
# ["", "full", "path", "to", "nowhere"],
# ["", "full", "path", "to"]
# 要素数が最大の物を一つ選ぶ。このあとで使うArray#zipでは、結果配列の各要素の長さがレシーバーの長さに制限されるから。
# 何を言っているか分からないと思うのでるりまを見られたい。
base = parts_list.max_by(&:length)
parts_list.delete base
p base # => ["", "full", "path", "to", "somewhere"]
pp parts_list
# => [["", "full", "path", "to", "anywhere"],
# ["", "full", "path", "to", "nowhere"],
# ["", "full", "path", "to"]]
# zipメソッドで、各階層のタプルを作る。
zipped = base.zip(*parts_list)
pp zipped
# => [["", "", "", ""],
# ["full", "full", "full", "full"],
# ["path", "path", "path", "path"],
# ["to", "to", "to", "to"],
# ["somewhere", "anywhere", "nowhere", nil]]
# 順番に調べて、行って、タプルの全要素が等くない物が出てきたらやめる。
commons = zipped.take_while {|tuple| tuple.uniq.length == 1}
pp commons
# => [["", "", "", ""],
# ["full", "full", "full", "full"],
# ["path", "path", "path", "path"],
# ["to", "to", "to", "to"]]
# 結果を元のパスの形に戻せば望みのパスが得られる。
common_prefix = commons.collect {|tuple| tuple.first}.join('/')
puts common_prefix
# => /full/path/to
なんか名前の付いた有名なアルゴリズムがありそうなんですけど、どうなんでしょう。
教えてください。