Help us understand the problem. What is going on with this article?

整数の集合を一発で剰余類に分けよう

More than 1 year has passed since last update.

例えば $\bmod 3$だったら

ns = range(30)
m = 3
list(zip(*zip(*[iter(ns)]*m)))
[(0, 3, 6, 9, 12, 15, 18, 21, 24, 27),
 (1, 4, 7, 10, 13, 16, 19, 22, 25, 28),
 (2, 5, 8, 11, 14, 17, 20, 23, 26, 29)]

となり,$3$ で割ったときの余りが $0$ のもの,$1$ のもの,$2$ のもので整数を分けることができます.数でないリストに突っ込んだ場合,中身を3つ飛ばしにしたものを1つの固まりにします.

ls = list('abcdefghijkl')
m = 3
list(zip(*zip(*[iter(ls)]*m)))
[('a', 'd', 'g', 'j'), ('b', 'e', 'h', 'k'), ('c', 'f', 'i', 'l')]

この記法がクールと思えるかどうかは分かりませんが,なぜこれでうまくいくかを簡単に説明しましょう.例えば

s = list(range(12))
s
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

を3つの数ずつに4分割するのに

list(zip(*[iter(s)]*3))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11)]

という方法があるのは割と有名だと思います.実は,公式チュートリアルのzip関数のところにいきなり書いてあります.

zip(*[iter(s)]*n) を使ってデータ系列を長さ n のグループにクラスタリングするイディオムが使えます。

よくよく眺めていると,この結果をzip関数に突っ込めば,3つ飛ばしのリストが出来上がることに気付くと思います.

list(zip(*zip(*[iter(s)]*3)))
[(0, 3, 6, 9), (1, 4, 7, 10), (2, 5, 8, 11)]

但し,この方法だと,10個の数のリストを3つの数ずつに分割しようとすると,半端な部分が切り捨てられてしまいます.

list(zip(*[iter(list(range(10)))]*3)) #9が切り捨てられる
[(0, 1, 2), (3, 4, 5), (6, 7, 8)]

これはzip関数の仕様です.これを回避するために,itertoolszip_longest関数が用意されています.

from itertools import zip_longest
list(zip_longest(*[iter(list(range(10)))]*3)) #半端なところにはNoneが入る
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, None, None)]

これを用いて,剰余類の方もアップデートしましょう.最後にNoneを取り除く行程があるのですが,tupleがイミュータブルである点は注意です.最終的には数学らしく,setの集まりにしました.

from itertools import zip_longest
ns = range(50)
m = 3
[{x for x in t if x != None} for t in zip(*zip_longest(*[iter(ns)]*m))]
[{0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48},
 {1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49},
 {2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47}]

zip関数は名前があまり好きじゃないのですが,奥が深いです.

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした