CodeIQ:ファイル名を作ろう

私自身が表題の問題を解いた時のプログラムについて解説します。
問題の詳細は「ファイル名を作ろう」(CodeIQ)を参照してください。

問題の概要

問題を引用します。
問題
ファイルをディレクトリ内に作成する際、同じ名前のファイルがあると、末尾に数字を付けるなどして同じ名前にならないようにします。
こうした処理をプログラムで書くことにします。

たとえば「dog」というファイルを作ろうとした場合、同じ名前のファイルが既にある場合は「dog_copy」という名前にします。「dog_copy」もある場合は「dog_copy2」という名前にします。「dog_copy2」もある場合は「dog_copy3」という名前にします。以下、末尾の数字が1ずつ増えていきます。
与えられる入力は、フォルダ内のファイル名のリストです。ただし、末尾の名前だけリストには含まれず、作成したいファイルの名前になります。

この末尾のファイル名を、上記の手順で変換して、作成可能なファイル名にします。そして、標準出力に出力して下さい。

下記では、「dog、tiger、dog_copy、rat、snake、monkey、snake_copy、rat_copy、snake_copy2、cat」がファイル名のリストで、「dog」が作成したいファイルの名前になります。
そして出力するファイル名は「dog_copy2」になります。

// 入力例
dog
tiger
dog_copy
rat
snake
monkey
snake_copy
rat_copy
snake_copy2
cat
dog
// 出力例
dog_copy2

私のプログラム

Rubyで解答しています。

#!/usr/bin/ruby

def solve(target, inputs)
	inputs.sort

	mx = -1
	for i in inputs
		next if i.index(target) != 0

		if i == target then
			mx = 0 if mx < 0
		elsif i == target + "_copy" then
			mx = 1 if mx < 1
		else
			rp = Regexp.new(target + "_copy")
			num = i.gsub(rp, "").to_i
			mx = num if mx < num
		end
	end

	if mx == -1 then
		return target
	elsif mx == 0 then
		return target + "_copy"
	else
		return target + "_copy" + (mx+1).to_s
	end
end

# main
inputs = []

while line = gets
	line.strip!
	next if line.empty?

	inputs << line
end

target = inputs.pop
puts solve(target, inputs)

解説

息抜き問題なので簡単です。

考え方

考え方というほどのものはありません。
対象のファイル名と先頭部分が一致するファイルだけをチェクし、一番大きい番号+1をつけるだけです。
このとき、「dog」しかない場合と「dog」と「dog_copy」しかない場合は特別に処理して0と1として扱います。

main

入力値をinputsに取得し、最後を除いてtargetに取っています。 solve()にtargetとinputsを渡して結果の文字列を印字します。

solve(target, inputs)

とりあえずinputsをソートします(必要ありませんでした)。

inputsの要素を順に繰り返し、targetと先頭が一致する文字列でなければ無視します(このコードは厳密にはバグ)。
文字列がtargetに一致していたら番号(mx)を0、target+"_copy"に一致していたらmx=1、それ以外なら「filename_cpoy数字」から「failname_copy」をから文字列に置換して数字だけを取り出しmxに代入します。

mx=-1ならそのファイル名は無いのでそのまま、mx=0なら_copy、それ以外なら_copy+(mx+1)をファイル名につけて出力すればOKです。

雑感

答え合わせのページにヒントがあって、確か1,2,3,…とカウントアップしながらファイル名を順次チェックし、見つからなくなったところでその値を使えば良い、という様な内容だったと思います。
このロジックより私のコードの方が少し効率が良いです。
ただ、「dog, dog_copy, dog_cpoy1, dog_copy3」の様に番号が跳んでいたら結果が異なってしまいますが、どちらを想定していたんだろう?