6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Python】シーケンスからn件ずつ取り出したい、n件未満でも取り出したい。

Last updated at Posted at 2019-02-16

概要

  • やりたかったこと
    • pythonでシーケンスからn件ずつ取り出してループしたい。
    • 末尾にn件未満の要素が残った場合、それも取り出したい。
  • 結論
    • ループの中でスライスを取る。
    • Iteratorとzipを使ったら、n件未満の要素が取り出せなかった(仕様通り)。
    • itertools.zip_longestを使うと、末尾に余分な要素が追加されてしまった(これも仕様通り)。
  • 環境
    • python3.6.7

本題

シーケンスから要素を何件かまとめて取り出したいケースって、たまにあると思います。100件のシーケンスから3件ずつ取り出す・・・というような感じです。
100件から3件ずつだと、最後は1件だけになります。この最後の1件を、1件しかないことを気にせずに取り出したい、というのがこの記事の目的です。

愚直にスライスを取る

この記事で意図通りに動くのはここだけです。
私はまだpythonを勉強がてらに始めたばかりなので、素直に考えつくのはこんな方法でした。

test_data = ['いちばん', 'にばん', 'さんばん', 'よんばん', 'ごばん']

# 最大で2つずつ取り出したい
size = 2

for start in range(0, len(test_data), size):
    print(test_data[start : start + size])

その出力

['いちばん', 'にばん']
['さんばん', 'よんばん']
['ごばん']

シンプルです。スライスを取る時に、シーケンスの範囲外を指定されてもエラーを起こさないという、pythonの優しさのおかげで、ループの最終3回目はtest_data[4:6]ですが問題なく取り出せます。

しかし、もしかしたら、もっと楽な、スマートな方法がないだろうか?と思って探してみました。
・・・探してみたけどうまくいかなかったので、試行錯誤は折り畳みます。

zipを使った場合(失敗しました)
## zipを使った場合 Googleさんにお伺いして、最初に見つけたのは大体こういった感じのコードでした。
test_data = ['いちばん', 'にばん', 'さんばん', 'よんばん', 'ごばん']
size = 2 # 最大で2つずつ取り出したい

iterator = iter(test_data)
for parted in zip(*[iterator]*size):
    print(parted)

上のコードの出力内容

('いちばん', 'にばん')
('さんばん', 'よんばん')

最後の要素が省かれてしまいます。
元々からしてzipは長さの違う複数のイテラブルを渡すな。という仕様なので、これはごもっともな動きです。

zip_longestを使った場合(これも失敗しました)
## zip_longestを使った場合 zip_longestだと渡されるイテラブルの長さがそれぞれ違っても、長い方に合わせてくれますが、長さが合わない場合、詰め物(無指定ならNone)をして返してくれます。
test_data = ['いちばん', 'にばん', 'さんばん', 'よんばん', 'ごばん']
size = 2 # 最大で2つずつ取り出したい

iterator = iter(test_data)
for parted in itertools.zip_longest(*[iterator]*size):
    print(parted)

上のコードの出力内容

('いちばん', 'にばん')
('さんばん', 'よんばん')
('ごばん', None)

最後にNoneが付いてきました。ケースバイケースで、これでいい場合もあると思いますが、今回は残念ながら違いました。
とはいえ、詰め物をしてくるのは使う前に知っていたので、これは仕方ない。

結論

素直にスライス取っちゃおうよ。ということになりました。

zipを使う方法は、**シーケンスの長さが一度に取り出したい数の倍数ぴったりなら、うまく行きます。**それでいいというケースも多々あるはずで、目的が違うなら仕方ないですね。
しかし、わざわざスライスを取る1行を省略できないか?1と思って探してみましたが、私が見つけられなかっただけかも知れないので、もしあったら知りたいところです。

  1. いっそのことイテラブルなクラスを書いてしまおうかと一瞬考えましたが、それじゃ本末転倒ですね。よほど同じ処理を繰り返すのでなければコードが増えるだけです。そして、そこまでこの処理を繰り返すコードは、ちょっと考えたくないですw

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?