summer_tree_home

Check iOでPython3をマスターするぜっ

Non-unique Elements (Check iO > Home)

どんな問題?

最初の問題は、Non-unique Elementsという名前だった。ようするに、ユニークでない要素だけを抽出すればいい。

いくつかの例が示されている。
checkio([1, 2, 3, 1, 3]) == [1, 3, 1, 3]
1と3はリストの中に2回ずつ出てくるから残す、2は1回しか出てこないから削除、ということ。

checkio([1, 2, 3, 4, 5]) == []
こちらは、すべての要素が1回しか出てこないから、全部削除している。

どうやって解くか?

要素がユニークかどうかは、リスト中に要素が何回出てくるかで判断できるだろう。つまり、2回以上出てくる要素を抽出すればよさそうだ。

というわけで、私が書いた答えがこれ。

def checkio(data):
    result = []
    for v in data:
        if data.count(v) > 1:
            result.append(v)
    return result

リストの中の各要素について、リスト中に出てくる回数が1より大きいなら、resultに追加していく、というもの。
Run&Checkをクリックすると、しばらく待たされて「Task solved!」の文字が。
楽勝だぜっ!と思って、他の人の回答を見ると・・・

他の人の答え

あー、そうか、内包表記(comprehension)を使えばいいんじゃん。

def checkio(data):
    return [v for v in data if data.count(v) > 1]

ぐはぁ。私の答えも間違いではないけど、くやしい。
ってか、Pythonはだいたいわかってるしー、なんて言ってたくせに、内包表記を忘れてた自分が恥ずかしい。

さらに別解

他の人の回答を見ていくと、よく分からないものがあった。

from collections import Counter

def checkio(data):
    count = Counter(data)
    count.subtract(set(data))
    return [x for x in data if x in +count]

なんだこりゃ?
Counterクラスは使ったことないけど、たぶん今回みたいにリスト要素の数を数えるためのクラスなんだろう。.subtract() は何をしてるんだ?引き算か?最後の +count って何だ??気持ち悪いぞ。

というわけで、調べてみた。

Counterは、要素を辞書のキーとして保存し、そのカウントを辞書の値として保存する、順序付けされていないコレクションです。
http://docs.python.jp/3.3/library/collections.html#collections.Counter

えーと、data=[1,2,3,1,3]として考えてみよう。

  1. まず、Counter(data)で、要素をカウントした辞書を作る。 {1: 2, 3: 2, 2: 1}
  2. set(data)でユニークな要素の集合を得る。 {1,2,3}
  3. subtract()で、それを引くことで、カウントを1ずつ減らす。 {1: 1, 3: 1, 2: 0}
  4. +count で、カウントが0かマイナスの要素を削除する。 {1: 1, 3: 1}

なるほど、つまり x in +count で、複数回出現した要素かどうか判定できるわけだ。全然知らなかったよ。(でもやっぱり+countって書き方はキモチ悪い。)


というわけで、1問目から勉強になりました。まだまだ未熟者です。