読者です 読者をやめる 読者になる 読者になる

Electronic Stationの1問目(Brackets)

CheckiO

ブログすっかりごぶさたでしたが、
Homeが終わって無料でやれるのが疎らだったので思わず課金してしまったりしてる程度に、
CheckiOは続けています。Electronic Stationの前半は比較的簡単でしたので足早に。

py.checkio.org

数式が正しいか判別する問題ですね。
とりあえず数式のうち括弧以外の要素を削除して、
閉じれた括弧は消すって感じでやってみようと思って色々やってて、
結局

def checkio(expression):
    brackets = "() {} "
    expression_brackets = ""
    for i in list(expression) :
        if brackets.count(i) > 0 :
            expression_brackets += i
    if len(expression_brackets) < 1 :
        return True
    if len(expression_brackets) %2 != 0 :
        return False
    while len(expression_brackets) > 1 :
        for i in brackets.split(" "):
            if expression_brackets.find(i) > -1 :
                deleted = expression_brackets.replace(i, "")
                expression_brackets = deleted
                break
            else :
                if i == brackets.split(" ")[2] :
                    return False
                    expression_brackets = ""
    return True

 で、解けました。
あまり綺麗ではないのでリファクタリング。。。

純粋に左カッコと右カッコを別に判別して、
左カッコがでてきた順にappend()して、
右カッコがでてきた順にpop()する感じとかでどうだろう。

def checkio(expression):
    brackets_open = ["(","{","["]
    brackets_close = [")","}","]"]
    expression_brackets =
    for i in expression :
        if i in brackets_open:
            expression_brackets.append(i)
        elif i in brackets_close:
            if len(expression_brackets) < 1 or expression_brackets.pop() != brackets_open[brackets_close.index(i)]:
                return False
return True if expression_brackets == [] else False

まぁ、少しマシになりましたかね。

支持率No1は

def checkio(data):
    stack=[""]
    brackets={"(":")","[":"]","{":"}"}
    for c in data:
        if c in brackets:
            stack.append(brackets[c])
        elif c in brackets.values() and c!=stack.pop():
            return False
    return stack==[""]

なるほどですね。
大枠の考え方はリファクタリング後のものと近いですが書き方は全然スマート。

うむ、頑張ろう。 

Homeの6問目(Open Labyrinth)

CheckiO

py.checkio.org

迷路のルートを見つける問題ですね。
最短でなくても、コースアウトさえしなければよいというかんじでしょうか。
進める方向は上下左右("S","N","W","E")のみ。
とりあえず現在地の上下左右が移動可能か判断して2方向以上移動可能だった場合、
元いた場所以外の方向に走査を進める、3方向以上であった場合、そこまでのbranchを作って元いた場所以外のどちらかに進む、1方向しかない場合直近のbranchまで戻る、branchがない場合は起点まで戻る。
って感じで考えてみたのですが、かなり複雑な感じでどはまりしました。

def checkio(maze_map):
    current = [1, 1]
    moves = [[1, 0], [-1, 0], [0, -1], [0, 1]]
    dist = ["S", "N", "E", "W"]
    dist_negative = ["N", "S", "W", "E"]
    movedlog = ""
    for i in range(15):
        S = [current[0]+moves[0][0], current[1]+moves[0][1], maze_map[current[0]+moves[0][0]][current[1]+moves[0][1]]]
        N = [current[0]+moves[1][0], current[1]+moves[1][1], maze_map[current[0]+moves[1][0]][current[1]+moves[1][1]]]
        E = [current[0]+moves[2][0], current[1]+moves[2][1], maze_map[current[0]+moves[2][0]][current[1]+moves[2][1]]]
        W = [current[0]+moves[3][0], current[1]+moves[3][1], maze_map[current[0]+moves[3][0]][current[1]+moves[3][1]]]
        distmap = [S, N, E, W]
        movable = {}
        movacount = 0
        for i, j in enumerate(distmap):
            if not j :
                movable.update({i : j})
                movacount += 1
        moved = movable.popitem()
        if movacount > 2 :
            altmove = movedlog[:]
            branch = current
            branchdist = moved
            branchalt = movable
            print("branchdist",branchdist)
        elif movacount < 2 :
            print(dist_negative[moved[0]])
            if dist_negative[moved[0]] == movedlog[len(movedlog)-1] :
                current = branch
                moved = branchalt.popitem()
        moveddist = dist[moved[0]]
        current = [current[0]+moves[moved[0]][0],current[1]+moves[moved[0]][1]]
        movedlog += moveddist

    print (movedlog)
    return "SSSSSEENNNEEEEEEESSWWWWSSSEEEESS"

一旦ループを15回にしてprintで吐き出しながら書いて見たのですが、
正直かなり無駄な感じでしんどかったのでこの方向は一旦ギブアップ。
とりあえず、色々調べて

http://qiita.com/MasayaMizuhara/items/86099ad721a329e1d6cd

を参考に、幅優先アルゴリズムで書いてみることに。

def checkio(maze_map):
    start = [1, 1]
    goal = [10, 10]
    moves = [[1, 0], [-1, 0], [0, -1], [0, 1]]
    dist = ["S", "N", "E", "W"]
    cue =
    movedlog =

    route =
    distlog = ""
    flag = True


    cue.append(start)
    while flag:
        moved = cue.pop()
        route.append(moved)
        S = [[moved[0]+moves[0][0], moved[1]+moves[0][1]], maze_map[moved[0]+moves[0][0]][moved[1]+moves[0][1]]]
        N = [[moved[0]+moves[1][0], moved[1]+moves[1][1]], maze_map[moved[0]+moves[1][0]][moved[1]+moves[1][1]]]
        E = [[moved[0]+moves[2][0], moved[1]+moves[2][1]], maze_map[moved[0]+moves[2][0]][moved[1]+moves[2][1]]]
        W = [[moved[0]+moves[3][0], moved[1]+moves[3][1]], maze_map[moved[0]+moves[3][0]][moved[1]+moves[3][1]]]
        distmap = [S, N, E, W]
        for i, j in enumerate(distmap) :
            if not j[1] :
                cue.append(j[0])
                if j[0] != goal :
                    if route.count(j[0]) > 0 :
                        cue.pop()
                else :
                    route.append(j[0])
                    flag = False
    print("cue", route)
    print(route)
    return "SSSSSEENNNEEEEEEESSWWWWSSSEEEESS"

なんか、だいぶ近づいた。。。んですかね?
あとはルートを変更した際の挙動をなんとかすればいけるんですかね。

あー、ようやく理解できました。
歩数を付け足すわけですね。
[歩数, x, y]]
で、前の歩数に対して足していく、
ルートが変わった場合、分岐時点の歩数から足していくと。

def checkio(maze_map):
    start = [[1, 1], 0]
    goal = [10, 10]
    moves = [[1, 0], [-1, 0], [0, 1], [0, -1]]
    dist = ["S", "N", "E", "W"]
    cue =
    movedlog =
    route =

    distlog = ""

    cue.append(start)
    while len(cue) > 0:
        moved = cue.pop()
        route.append(moved)
        movedlog.append(moved[0])
        S = [[moved[0][0]+moves[0][0], moved[0][1]+moves[0][1]], maze_map[moved[0][0]+moves[0][0]][moved[0][1]+moves[0][1]]]
        N = [[moved[0][0]+moves[1][0], moved[0][1]+moves[1][1]], maze_map[moved[0][0]+moves[1][0]][moved[0][1]+moves[1][1]]]
        E = [[moved[0][0]+moves[2][0], moved[0][1]+moves[2][1]], maze_map[moved[0][0]+moves[2][0]][moved[0][1]+moves[2][1]]]
        W = [[moved[0][0]+moves[3][0], moved[0][1]+moves[3][1]], maze_map[moved[0][0]+moves[3][0]][moved[0][1]+moves[3][1]]]
        distmap = [S, N, E, W]
        for i, j in enumerate(distmap) :
            if not j[1] :
                cue.append([j[0], moved[1]+1])
            if j[0] != goal :
                if movedlog.count(j[0]) > 0 :
                    cue.pop()
            else :
                route.append([j[0], moved[1]+1])
                cue =
    checker = route.pop()
    routelist =

    while len(route) > 0 :
        checked = route.pop()
        if checker[1] - 1 == checked[1] :
            routelist.append([checker[0][0]-checked[0][0], checker[0][1]-checked[0][1]])
        checker = checked
        routelist.reverse()
        for i in routelist :
            for n, m in enumerate(moves) :
                if i == m :
                    distlog += dist[n]
    return distlog

いやー、これに3日くらい使いました。。。
そしてリファクタリングする気にもなりません。。。
で、評価されてる回答見るのはすごい時間かかりそうだったので、
ランダムに見ていった中で好きだったのが下記です。

def checkio(maze):
    q = [(1,1)]
    maze[1][1] = ''
    for i, j in q:
        for move, I, J in zip('NSWE', (i-1,i+1,i,i), (j,j,j-1,j+1)):
            if maze[I][J] == 0:
                maze[I][J] = maze[i][j] + move
                q += [(I,J)]
                if I == J == 10:
                    return maze[I][J]

超シンプル!!!!
うーん。これはどういう知識があれば思い付くのだろう。。
やっていることとしては全探索だけど、
ここまでシンプルにできるんですね。

勉強しよう。

Homeの5問目(Min and Max)

CheckiO

py.checkio.org

組み込み関数であるmax()とmin()を自力で実装するという問題ですね。
最低限の実装としては引数のargsをソートして最大もしくは最小を取り出すって感じでどうでしょう。
もう一つの引数であるkeyの扱いは少し悩ましい感じなのですが。
とりあえず、keyの扱いは置いておいて上記の方法で使えそうな関数を調べると、
配列をソートするsorted()って関数を発見。

http://docs.python.jp/2/howto/sorting.html

しかもkeyも普通に使えるという素晴らしさですね。
ということでさっくり、

def min(*args, **kwargs):
    key = kwargs.get("key", None)
    if len(args) > 1:
        result = sorted(args, key=key)[0]
    else :
        result = sorted(args[0], key=key)[0]
    return result

def man(*args, **kwargs):
    key = kwargs.get("key", None)
    if len(args) > 1:
        result = sorted(args, key=key, reverse=True)[0]
    else :
        result = sorted(args[0], key=key, reverse=True)[0]
    return result

でいけてしまいました。
残念なところとしてはargsがイテラブルなのか違うのかの判別方法がなかったので、
argsの長さで調べるという手段しかみつけられなかったことでしょうか。
あとは書き方でJSなんかで使える「?」での分岐(三項演算子っていうんですね)が使えればもう少し綺麗に書けそうなのに、
と思って調べてみると

http://qiita.com/howmuch/items/bf6d21f603d9736fb4a5

という素敵なのがあったので、それを使って書き直しました。

def min(*args, **kwargs):
    key = kwargs.get("key", None)
    result = sorted(args, key=key)[0] if len(args) > 1 else result = sorted(args[0], key=key)[0]
    return result

def man(*args, **kwargs):
    key = kwargs.get("key", None)
    result = sorted(args, key=key, reverse=True)[0] if len(args) > 1 else result = sorted(args[0], key=key, reverse=True)[0]
    return result

 

ちょっと三項演算子のところが冗長的ではありますが、
個人的に許せる範囲だったので一旦終了。
ちなみに高評価回答はkeyの処理を引数内で行ってるのとargsの判別を関数組んでる感じですかね。

def get_first_from_sorted(args, key, reverse):
    if len(args) == 1:
        args = iter(args[0])
    return sorted(args, key=key, reverse=reverse)[0]

def min(*args, key=None):
    return get_first_from_sorted(args, key, False)

def max(*args, key=None):
    return get_first_from_sorted(args, key, True)

とりあえず5問目は前の数題より全然簡単で少し驚きました。

Homeの4問目(Pawn Brotherhood)

CheckiO

py.checkio.org

チェスのポーンに関する問題で、
自軍にn個のポーンがあるとき安全なポーン(他のポーンに守られている)の総数を導き出すというものです。
まずポーンの性質ですが斜め前(左右)に1マスずつしか進めません。つまり安全なポーンとは他のポーンの斜め前(左右)にあるポーンということになります。
またポーンの配置数は最大で8でポーンの位置はローマ字と数字の組み合わせ盤面のマスを表したもので与えられます。

一旦考え方として一個ずつ配置済みポーンの座標から安全な座標を洗い出して、その座標上にあるポーンの数を数えるという方向性でやってみました。

前述したように配置済みのポーンの座標は
{"b4", "d4", "f4", "c3", "e3", "g5", "d2"}
というローマ字と数字の組み合わせで形で与えられます。
ちなみにpythonの中括弧はディクショナリ(連想配列)らしですね。
でも、キーがない場合の連想配列ってなんなんでしょうか?
イテラブルであるということを便宜的に表現してるだけなんですかね?
とりあえず普通の配列として扱ってみるか、と思ってやってみたのですがうまく取り出せない。。
で、色々やった結果list()で通常の配列に変換できたので一旦それでなんとかしいてみました。

重複を外すのを忘れててのエラーが出たりはしたもののとりあえず下記で通りました。

def safe_pawns(pawns):
    safespots =
    cols = { "a":0, "b":1, "c":2, "d":3, "e":4, "f":5, "g":6, "h":7 }
    pawns = list(pawns)
    for i in pawns:
        target =

        for j in pawns:
            if int(i[1])+1 == int(j[1]):
                target.append(j)
         for k in target:
            if abs(cols.get(i[0])-cols.get(k[0])) == 1:
                safespots.append(k)
                if safespots.count(k)>1:
                    safespots.pop()
    return len(safespots)

とはいえforがいっぱいで気持ち悪いので書き換えたいですね。
上記でやっている、一個取り出して安全な行i[1] + 1にあるpawnを引っ張って、
i[0]-j[0]の絶対値が1のものがあったら安全なポーンをカウントしている配列を調べて重複がなければ入れる。
という処理あたりが改善しやすそうということでそのあたりを中心に検討していたのですが、行を評価してということをやるよりダイレクトに座標を出した方が簡単になりそうです。

def safe_pawns(pawns):
    safespots =
        cols = { "a":0, "b":1, "c":2, "d":3, "e":4, "f":5, "g":6, "h":7 }
        pawns = list(pawns)
        for i in pawns:
            saferow = i[1]+1
            safeL = cols.key(cols.get(i[0])-1) + saferow
            safeR = cols.key(cols.get(i[0])+1) + saferow
            if safeL in pawns:
                if safespots.count(safeL) < 1: safespots.append(safeL)
            if safeR in pawns:
                if safespots.count(safeR) < 1: safespots.append(safeR)
    return len(safespots)

strだったりintだったりが入り混じりすぎて細々エラーが出ていたので、
修正していたら配列の長さを超えて取得しようとしてるというエラーが出てたので修正。

def safe_pawns(pawns):
    safespots =
    cols = { "a":0, "b":1, "c":2, "d":3, "e":4, "f":5, "g":6, "h":7, "":"" }
    pawns = list(pawns)
    for i in pawns:
        saferow = int(i[1])+1
        safeL = list(cols.keys())[cols.get(i[0])-1] + str(saferow)
        safeR = list(cols.keys())[cols.get(i[0])+1] + str(saferow)
        if safeL in pawns:
            if safespots.count(safeL) < 1: safespots.append(safeL)
        if safeR in pawns:
            if safespots.count(safeR) < 1: safespots.append(safeR)
    return len(safespots)


もう少しなんとかしたい、
ということで色々調べた結果ord()でASCIIコードを拾えてchr()で戻せるみたいですね。

def safe_pawns(pawns):
    safespots =
    for i in pawns:
        saferow = str(int(i[1])+1)
        safeL = chr(ord(i[0])-1)+saferow
        safeR = chr(ord(i[0])+1)+saferow
        if safeL in pawns:
            if safespots.count(safeL) < 1: safespots.append(safeL)
        if safeR in pawns:
            if safespots.count(safeR) < 1: safespots.append(safeR)
    return len(safespots)

基準とするポーンの座標を守る側ではなく守られる側にすると変なifが外せることに築いたので修正しました。

def safe_pawns(pawns):
    safespots =
    for i in pawns:
        saferow = str(int(i[1])-1)
        safeL = chr(ord(i[0])-1)+saferow
        safeR = chr(ord(i[0])+1)+saferow
        if safeL in pawns or safeR in pawns:
            safespots.append(i)
    return len(safespots)

まぁ、あとは一々配列に入れて長さを返すんじゃなくて純粋にカウントしてその数字を返すようにするというのでもう少し綺麗にできますね。
とはいえ、一旦満足したので以上でいつも通り幾つかの回答をチェック。
一番評価されてるのは下記になります。
個人的には若干無理に一行にまとめてる感があってあまり好きくない感じです。

def safe_pawns(pawns):
    answer = 0
    for pawn in pawns :
        if chr(ord(pawn[0])-1)+str(int(pawn[1])-1) in pawns or chr(ord(pawn[0])+1)+str(int(pawn[1])-1) in pawns : answer +=1
    return answer

とりあえず、CheckiOは一問解くのに無駄に時間がかかりますね。
まぁ、考えるのも楽しいので良いのですけどね。

 

Homeの3問目 (Cipher Map)

CheckiO

py.checkio.org

4掛け4のグリッドのマスにそれぞれ適当な文字を組み込んで、
同じ4掛け4サイズのグリッドの内4マス穴の空いたグリッドをかぶせて穴から覗く文字を取り出す、
90度ずつローテーションさせて合計16文字のパスワードを取り出す。
という暗号化の仕組みを解読するコードを書くという問題ですね。
とりあえず、2次元配列的な感じでやってみることに。
正直無駄な処理だらけではあるけれど、

def recall_password(cipher_grille, ciphered_password):
    result = ''
    grille_2d = [list(cipher_grille[0]),list(cipher_grille[1]),list(cipher_grille[2]),list(cipher_grille[3])]
    password_2d = [list(ciphered_password[0]),list(ciphered_password[1]),list(ciphered_password[2]),list(ciphered_password[3])]
    t = 0
    while t < 4:
        pickedchar = ''
        for i,n in enumerate(grille_2d):
            for j, m in enumerate(n):
                if m == 'X' :
                    pickedchar += password_2d[i][j]
        result += pickedchar
        tmp_grille_2d=
        grille_2d.reverse()
        for a, b, c, d in zip(*grille_2d):
            tmp_grille_2d.append([a, b, c, d])
        grille_2d =

        grille_2d = tmp_grille_2d
        t += 1
    return result

で一旦解けました。
リストをいちいち書くのは少し残念すぎる気がするのでforで回すようにして、
whileで残念な書き方になっていたところをfor ... in range()で置き換え。

def recall_password(cipher_grille, ciphered_password):
    result = ''
    grille_2d, password_2d = ,
    for i, j in zip(cipher_grille,ciphered_password):
        grille_2d.append(i)
        password_2d.append(j)
    for t in range(4):
        pickedchar = ''
        for i,n in enumerate(grille_2d):
            for j, m in enumerate(n):
                if m == 'X' :
                    pickedchar += password_2d[i][j]
        result += pickedchar
        tmp_grille_2d=
        grille_2d.reverse()
        for a, b, c, d in zip(*grille_2d):
            tmp_grille_2d.append([a, b, c, d])
        grille_2d =

        grille_2d = tmp_grille_2d
    return result

そもそも、いちいち配列にする必要ないような気がしたので、
書き換えようとしたものの回転させることができず下記でギブアップ

def recall_password(cipher_grille, ciphered_password):
    result = ''
        for i, j in zip(cipher_grille,ciphered_password):
            for n, m in enumerate(i):
                if m == 'X' :
                    print(j[n])
    return result

最初に位置を出してあとは追ってくって感じで'X'の位置を座標に変換して回すとかどうだろうとか思ったけど、
読み出す順序を考えると結構無駄な処理が増えそうな気もする。。。
ということで、

def recall_password(cipher_grille, ciphered_password):
    result = ''
    grille_2d, password_2d = ,
    for i, j in zip(cipher_grille,ciphered_password):
        grille_2d.append(i)
        password_2d.append(j)
    for t in range(4):
        for i,n in enumerate(grille_2d):
            for j, m in enumerate(n):
                if m == 'X' :
        result += password_2d[i][j]
        tmp_grille_2d=[]
        grille_2d.reverse()
        for a, b, c, d in zip(*grille_2d):
            tmp_grille_2d.append([a, b, c, d])
        grille_2d = tmp_grille_2d
    return result

この辺が一旦落とし所でしょうか。。

さて、他の人の回答を見ると、

def recall_password(grill, cypher):
    password = ""
    for _ in grill: # must be of len 4
        for grill_row, cypher_row in zip(grill, cypher):
            for grill_letter, cypher_letter in zip(grill_row, cypher_row):
                if grill_letter == 'X':
                    password += cypher_letter
        row1, row2, row3, row4 = grill
        grill = tuple(zip(row4, row3, row2, row1)) # rotate
    return password

あー、後半の処理のところを逆に並べてzipするということなんですね。
でも、基本的には

row1, row2, row3, row4 = grill

を発想できませんでした。。
うむむむ。

def recall_password(cipher_grille, ciphered_password):
    result = ''
    for t in range(4):
        for i, j in zip(cipher_grille,ciphered_password):
            for n, m in enumerate(i):
                if m == 'X' :
        result += j[n]
        a, b, c, d = cipher_grille
        cipher_grille = tuple(zip(d, c, b, a))
    return result

なるほどですね。

Homeの2問目 (Roman Numerals)

CheckiO

週末は家族サービスに追われていてブログすら書けないという状況でした。
とはいえCheckiOは1問くらいやってみました

py.checkio.org

通常使われているアラビア数字をローマ数字(I、II、IV、XIみたいなやつ)に変換する(1〜3,999まで)という問題ですね。

ローマ数字は10進数に基づいていますが、位取りが直接的でなく、ゼロを含める事ができません。 ローマ数字は以下の7つの記号の組み合わせで構成されています。

  • 記号とその値
  • I 1 (unus)
  • V 5 (quinque)
  • X 10 (decem)
  • L 50 (quinquaginta)
  • C 100 (centum)
  • D 500 (quingenti)
  • M 1,000 (mille)

ローマ数字に関する、より詳細な情報は Wikipediaの記事 より参照できます。

 

という事で、wikipediaを見ると

ただし、同じ文字を4つ以上連続で並べることはできない。そのため、例えば 4 は「IIII」、9は「VIIII」とは表現できない。この場合は小さい数を大きい数の左に書き、右から左を減ずることを意味する。これを減算則という。

なので4は「IV」9は「IX」と言った書き方になります。

まず考え方ですが、数字を桁ごとに分解して配列に入れて一つづつ評価するって方向性を検討してみました。
与えられた引数の各桁の数字をそれぞれ「1〜3」、「4〜8」、「9」でパターン化して、桁ごとに代入するローマ数字をかえるみたいな方向性も考えたのですが、それはそれで分岐が多そうだったので桁ごとローマ数字を数字を配列に突っ込んで、それを別の配列に突っ込んであとは元の数字を分解して各桁ごとに評価するってことで、

def checkio(data):
    unus = ["I","II","III","IV","V","VI","VII","VIII","IX"]
    decem = ["X","XX","XXX","XL","L","LX","LXX","LXXX","XC"]
    cetum = ["C","CC","CCC","CD","D","DC","DCC","DCCC","CM"]
    mille = ["M","MM","MMM"]
    digitlist = [unus,decem,cetum,mille]
    datalist = [int(i) for i in list(str(data))]
    Romandigit = ""
    i = 0
    while 0 < len(datalist):
        n = datalist.pop()
        Romandigit = digitlist[i][n-1]+Romandigit
        i = i+1
return Romandigit

って感じでやってみました。

ら、10の時につまづいてしまいました。ケアレスミスですね。
次の桁に行った時は一個前の桁は必要ないので、nが0の時は文字列に追加する処理をスキップしてあげるという形で対処してみました。

def checkio(data):
    unus = ["I","II","III","IV","V","VI","VII","VIII","IX"]
    decem = ["X","XX","XXX","XL","L","LX","LXX","LXXX","XC"]
    cetum = ["C","CC","CCC","CD","D","DC","DCC","DCCC","CM"]
    mille = ["M","MM","MMM"]
    digitlist = [unus,decem,cetum,mille]
    datalist = [int(i) for i in list(str(data))]
    Romandigit = ""
    i = 0
    while 0 < len(datalist):
        n = datalist.pop()
        if n != 0 :
            Romandigit = digitlist[i][n-1]+Romandigit
            i = i + 1
return Romandigit

一旦解けました。
とりあえず、whileよりforだろとか無駄な分岐とかあるので修正しました。

def checkio(data):
    unus = ["","I","II","III","IV","V","VI","VII","VIII","IX"]
    decem = ["","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"]
    cetum = ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"]
    mille = ["","M","MM","MMM"]
    digitlist = [unus,decem,cetum,mille]
    datalist = [int(i) for i in list(str(data))]
    datalist.reverse()
    Romandigit = []
    for i, n in enumerate(datalist):
        Romandigit.append(digitlist[i][n])
        Romandigit.reverse()
return ''.join(Romandigit)

無駄なところを削りました。
ただ、悲しいかなこれ以上なんとかすることが難しかったです。
評価が高い回答を見ると

def checkio(n):
    result = ''
    for arabic, roman in zip*1:
        result += n // arabic * roman
        n %= arabic
return result

なるほどなぁ。
見やすいし分かりやすい。
って言ってもzip関数とか色々わからなくて悩んだけど。

n %= arabic

は全く思いつかなかった。

世の中頭の良い人は多いんですね。

*1:1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1),
        'M CM D CD C XC L XL X IX V IV I'.split(

Homeの1問目(Non-unique Elements)

CheckiO

ブログも毎日更新のつもりだったのですが、
早速ながらサボるという残念極まりないことをしでかしてしまいました。
ただ、pythonの勉強の方はきちんと続けています。
といっても、CheckiOの課題を順を追ってやってるだけですし、
非常にスローペースなんですがしばらくはこれを続けようかなと思っています。

ということで、CheckiOの自分の回答コードをひたすら晒していきます。
最終版じゃない過程も晒していくので匿名でも無駄に恥ずかしいです。

py.checkio.org

リストの中から重複している(ユニークでない)数字だけを取り出すという問題ですね。
とりあえず、配列内の数字を一つづつ取り出して総当てして重複した場合、別の配列に突っ込んでいくという感じで解いてみました。

var 1 :
for文がうまく書けなかったのでwhileを使うというとても残念な感じです。

def checkio(data):
    arr=
    i = 0
    while i < len(data[:]):
        n = 0
        t = 0
        while n < len(data[:]):
            if data[i] == data[n]:
                t = t+1
                if(t > 1):
                    arr.append(data[n])
                    break
            n = n+1
        i = i + 1

return arr

var 2 :
for文がfor..in..しかないと分かったんでwhileを使っていたところをforで書き直してみました。
ifが二重になっているのを省きたい気がしますね。

def checkio(data):
    arr=
        for i in data:
            t = 0
            for n in data:
                if i == n:
                    t = t + 1
                    if t > 1:
                        arr.append(n)
                        break

return arr

 

var 3 :
ifの重複はなんともできなかったのですがrangeを使って変な変数を削りました。

def checkio(data):
    arr=
    for i in range(len(data)):
        for n in range(len(data)):
            if i != n:
                if data[i] == data[n] :
                    arr.append(data[n])
                    break

return arr

 

var 4 :
回答のところに

#You can use list.count(element) method for counting.
#Create new list with non-unique elements
#Loop over original list

って書いてありましたね。。。
countを使うとlist内のエレメント数をカウントできると。
ちゃんと読まないとダメですね。

def checkio(data):
    arr =
    for i in data:
        if data.count(i) > 1:
            arr.append(i)
return arr

ということで、自分としてはこれくらいでいいかなと思ったのですが、
他者の回答を見るとまさかの1行。

checkio=lambda d:[x for x in d if d.count(x)>1]

なるほどなぁ。。。
lambdaっていうのは無名関数なんですね。
jsでいうと、
checkio=function()
みたいな感じですかね。

とりあえず引き続き頑張ります。