質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

4717閲覧

dequeから範囲を指定して値を取得

sayaka1202

総合スコア18

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

2クリップ

投稿2019/02/02 21:37

編集2019/02/03 06:46

やりたいこと

dequeで範囲を指定して値を取得したい。
調べても出てこなかったので、無理そうならlistに変換しようと思いますが、
スマートな方法があればご教授ください。

_deque = collections.deque(maxlen=1000) for i in range(1000) _deque.append(i) # 1000個の値がappendされた状態で末尾から100個、500個のように任意の値を取得したい。(取り出しはしなくてよい)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

itertools.isliceを使うと良いと思います。-> ドキュメント

islice

投稿2019/02/03 05:05

YouheiSakurai

総合スコア6142

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

quickquip

2019/02/03 07:19

dequeに対してisliceを使ってしまっては、dequeを使う意味がなくなるでしょう。
YouheiSakurai

2019/02/03 07:39

私がitertools.isliceを良いと思った理由は「Simple is better than complex.」と「itertoolsがCで実装されているから」です。「dequeを使う意味がなくなる」はitertools.isliceが良くないとする理由としては少し変じゃないですか?dequeを使うその前提で何がスマートかと考えた結論が私の回答です。
quickquip

2019/02/03 08:27

dequeを使う意味はappendとpopがO(1)の速度でできる点と、rotateがCで実装されていて高速な点にあります。それらの操作を「使わない」isliceを選ぶということは、dequeを使う意味を「無くす」ことに等しいと思います。 大きいdequeからたくさんの部分要素を取り出すならpopを繰り返すのは不利で、isliceの方がいいのですが、「大きいdequeからたくさんの部分要素を取り出す」という前提自体がdeque向きじゃない、という意味でもあります。
Zuishin

2019/02/03 08:53

他のところで deque の利点を生かしてるなら別にここで生きてなくても使う意味あるんじゃないですか? そもそもそこまで速度が必要なものかどうかも疑問です。 1000 程度の数では、データ型を変更しなければならないほどの差は出ないと思います。
quickquip

2019/02/03 09:16 編集

なるほどその通りです。納得しました。 dequeを使う局面を考えると確かに、"この部分を高速にしたい"欲求はそれほどなさそうです。
YouheiSakurai

2019/02/03 10:38

quiquiさん、「dequeを使う意味」は他にもありますよ。dequeはmaxlenからあぶれた要素への参照が勝手に切れるのでweakref.WeakSet等と組み合わせると面白い使い方ができます。ご参考までに。https://teratail.com/questions/168245#reply-251105
guest

0

ベストアンサー

一般的にこれが最良という方法はありません。
dequeはどういうアルゴリズムで動いているかを中までわかった上でないと速くならないし、実際にどのぐらいのデータをどのように扱うかを前提にしないと使うべきなのか判断できない、かなり低水準なライブラリなのです。
(だからこそスライス実装を提供していないように思えます)

長いdequeから、少数の末尾を取り出すだいたいは速い方法は

python

1def slice_last_n(d, n): 2 t = [d.pop() for _i in range(n)][::-1] 3 d.extend(t) 4 return t

こうでしょう。(もっときれいに書けないか……、という気はします)

ipythonの%timeitでの計測

plain

1In : x = deque(range(1000000), 1000000) 2 3In : %timeit y = slice_last_n(x, 100) 49.9 µs ± 175 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 5 6In : %timeit y = list(x)[-100:] 711 ms ± 131 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

でも長いdequeから、長い末尾を取り出すならlistにする方が速いです。

plain

1In : %timeit y = slice_last_n(x, 900000) 2106 ms ± 653 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) 3 4In : %timeit y = list(x)[-900000:] 519.3 ms ± 429 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

質問のような短いdequeから、短い末尾を取り出すなら、だいたいはlistにするのが速く、コードもわかりやすいはずです。

plain

1In : x = deque(range(1000), 1000) 2 3In : %timeit y = slice_last_n(x, 100) 410.3 µs ± 282 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 5 6In : %timeit y = list(x)[-100:] 75.93 µs ± 636 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

追記

https://docs.python.org/ja/3/library/collections.html#deque-recipes

To implement deque slicing, use a similar approach applying rotate() to bring a target element to the left side of the deque. Remove old entries with popleft(), add new entries with extend(), and then reverse the rotation. With minor variations on that approach, it is easy to implement Forth style stack manipulations such as dup, drop, swap, over, pick, rot, and roll.

python

1def slice_deque(d, i, n): 2 d.rotate(-i) 3 t = [d.popleft() for _i in range(n)] 4 d.extend(t) 5 d.rotate(i+n) 6 return t

plain

1In : x = deque(range(1000000), 1000000) 2 3In : %timeit y = list(islice(x, 100, 10)) 4808 ns ± 12.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 5 6In : %timeit slice_deque(x, 100,10) 71.99 µs ± 52.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 8 9In %timeit y = list(islice(x, 700000, 10)) 102.31 ms ± 44.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) 11 12In : %timeit slice_deque(x, 700000,10) 13257 µs ± 19.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

追記
長いdequeから、長い部分要素を取り出すならisliceの方が有利です。(popを繰り返す操作がネックになりますから)

plain

1In : %timeit y = list(islice(x, 700000, 100000)) 22.21 ms ± 24.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) 3 4In : %timeit slice_deque(x, 700000, 100000) 59.72 ms ± 48.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

投稿2019/02/03 00:07

編集2019/02/03 08:29
quickquip

総合スコア11038

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問