連続する数列をハイフンでまとめるシェルスクリプト – ザリガニが見ていた…。を見て、面白いことをやっているので Python でやってみた。
cf. Rubyでどう書く?:連続した数列を範囲形式にまとめたい – builder by ZDNet Japan (元記事)
def diff(a): return map(lambda x, y: x - y, a[1:], a[:-1]) def hyphenate_num(s): a = map(lambda x: int(x), s.split()) d = diff(a) b = map(lambda x, y: (x, y), a, d) r = [] flg = False for x in b: if x[1] > 1: r.append(str(x[0])) r.append(', ') flg = False elif x[1] == 1: if not flg: r.append(str(x[0])) r.append('-') flg = True else: r.append(str(x[0])) return ''.join(r) if __name__ == '__main__': print hyphenate_num("1 2 3") print hyphenate_num("1 2 3 5 7 8") print hyphenate_num("1 3 4 5 7")
実行結果:
^o^ > python hyphenate_num.py 1-3 1-3, 5, 7-8 1, 3-5, 7
あんまりきれいなコードじゃないけどできた。やっぱりreduceを使うのほうがいいのかなあ。
挑戦してみましたが、
なかなかエレガントかつわかりやすく書くのは難しいですね。。
from itertools import groupby,chain
unpackdiff = lambda (x,y):x-y
def hyphenate(s):
nums = map(int,s.split())
for diff, g in groupby(zip(nums,nums[1:]),unpackdiff):
seqs = list(g)
if diff == -1:
yield seqs[0][0],’-‘,seqs[-1][1]
else :
yield chain(*((a,’, ‘,b) for a, b in seqs))
def create_hyphenated(s):
return ”.join(str(k) for k,_ in groupby(chain(*hyphenate(s))))
if __name__ == ‘__main__’:
print create_hyphenated(“1 2 3”)
print create_hyphenated(“1 2 3 5 7 8”)
print create_hyphenated(“1 3 4 5 7”)
使っているパーツは違いますが、
基本的な考え方は大きくは変わらないかと思います。
工夫と言えばgroupbyを使った重複削除くらいでしょうか。
余談ですが、
map(lambda x: int(x), s.split()) は単に map(int, s.split())、
map(lambda x, y: (x, y), a, d) は単にzip(a,d)
とすれば、よりすっきりすると思います。