compact-number-list

昨日のひげぽんさんのお題のPython版。

def compact_number_list(L):
    if len(L) < 2:
        return L
    L2 = [[L[0]]]
    for i, v in enumerate(L[1:]):
        if L2[-1][-1] + 1 == v:
            L2[-1].append(v)
        else:
            L2.append([v])
    L3 = []
    for vs in L2:
        if len(vs) == 1:
            L3.append(vs[0])
        else:
            L3.append([vs[0], vs[-1]])
    return L3
	
print compact_number_list([1, 3, 4, 5, 6, 12, 13, 15])  #=> [1, [3, 6], [12, 13], 15]

結局CortYumingさんと同じアルゴリズムになってしまった。別解や昨日の発展問題はあとでまた考えるつもり。


追記(2008/9/28):

itertools.groupbyを使った方法。あと3項演算子使ってみた。

from itertools import groupby

def compact_number_list(L):
    def kf(x):
        if kf.prev:
            if kf.prev+1 == x:
                kf.prev = x
                return kf.cnt
            else:
                kf.cnt += 1
                kf.prev = x
                return kf.cnt
        else:
            kf.prev = x
            return kf.cnt
    kf.prev = None
    kf.cnt = 1
    L2 = []
    for k, g in groupby(L, kf):
        L_ = list(g)
        is_not_scalar = len(L_)!=1
        L_ = [L_[0], L_[-1]][0:[1, 2][is_not_scalar]]
        L2.extend([L_, [L_]][is_not_scalar])
    return L2
	
print compact_number_list([1, 3, 4, 5, 6, 12, 13, 15])  #=> [1, [3, 6], [12, 13], 15]

groupbyは以下のようにkf(x)の値が同じになるxをグループ分けする。

kf(x)  [x]
-------------------
1      [1]
2      [3, 4, 5, 6]
3      [12, 13]
4      [15]

3項演算子は以下の3通りやり方がある。

a if is_a else b # 2.5以上

is_a and a or b  # aの部分がNoneやFalseになる場合
                 # [is_a and [a] or [b]][0]のようにリストかタプルでくくる必要がある
                 # もしくは、[res] = is_a and [a] or [b]

[a, b][is_not_a] # False==0, True==1であることを利用している