Pythonでリストの内包表記を使って2次元リストを1次元リストにする
やりたかったことは
list = [[1, 3, 5], [2,4]]
こういう2次元のリストを
[1, 3, 5, 2, 4]
こういう1次元リストにしたくてどうすればいいのかなぁと。
for文作ればすぐできそうだったのですが、大した処理でもないので1行で書けないのかなと思いました。
「多分、こういうときはリストの内包表記ってやつを使うんだろうな」と予測を立てて、まずはググった。
まずは「python 2次元 1次元 リスト 内包表記」ってキーワードでググったけども上手くヒットせず。
「内包表記とかがダメなのかなぁ?」と思ってキーワードから抜いても上手くヒットせず。
色々試したけどどうもヒットしない。
あんまり需要ないのかもしれないなと思い、自分で組み立て。
>>> list = [[1, 3, 5], [2, 4]] >>> [item for item in v for v in list] Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'v' is not defined
何かエラー出た。なんだこれ。
頭の中で「listをforで回して[1, 3, 5]と[2, 4]を取り出して、その後さらにそれぞれその中を表示すればいいんだよな」と思って作った式が上のやつ。
for文使ってそのまま書くと
>>> items = [] >>> for v in list: ... for item in v: ... items.append(item) ... >>> items [1, 3, 5, 2, 4]
いけた。あれ…いけるじゃないか。
何が間違ってたかわからなくてチュートリアルを確認。
>>> vec1 = [2, 4, 6] >>> vec2 = [4, 3, -9] >>> [x*y for x in vec1 for y in vec2] [8, 6, -18, 16, 12, -36, 24, 18, -54] >>> # 訳注: 上記の内包表記をループで書きなおすと、こうなります。 >>> L = [] >>> for x in vec1: ... for y in vec2: ... L.append(x*y)
あれ?あれ?前のforから読むの?Perlのmapみたいに後ろから見てけばいいものかと思ったのに。
もう少し読み進めると、
ノート
訳注: 内包表記の中に for や if が複数回現れる場合、 左側の for, if が、内包表記ではなくループで書いた場合の 外側のブロックになります。 上の例はまだ判りやすいですが、複雑な内包表記はすぐに読みにくくなってしまうので、 その場合はループで書き下した方が良いでしょう。
なるほど。そうなのね。だからvが定義されてないってエラー出たのか。for文が複数ある場合は前から見ていいのね。
ということで初めに書いた式のfor文を入れ替えて以下のようにしたら上手くいきました。
>>> list = [[1, 3, 5], [2, 4]] >>> [flatten for inner in list for flatten in inner] [1, 3, 5, 2, 4]
余談ですが、これ書きながら「そういえば1次元配列にするときにflattenって変数名や関数名使うのみたことあるな」と思い、キーワードを「two-dimensional python list flatten」にしてみたら結構出てきました。
例えば下のやつ。
- http://stackoverflow.com/questions/103844/how-do-i-merge-a-2d-array-in-python-into-one-string-with-list-comprehension
- http://stackoverflow.com/questions/2961983/convert-multi-dimensional-list-to-a-1d-list-in-python
ふーむ。全く同じことやってる。ググる能力が足りなかった。