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

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

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

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

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

Q&A

解決済

2回答

2314閲覧

スライスのステップは,起点をどのように決めるのか

liveasnotes

総合スコア1284

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

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

2グッド

1クリップ

投稿2018/08/27 09:50

編集2018/08/27 13:46
  • リスト[1,2,3,4,5,6,7,8,9,10][:-3:-1]でスライスした結果が[10,9]になる
  • 本当は[10,9,8]を得たかった
  • 色々試してみると,[:-4:-1][-1:-4:-1]が返す値が同じであることは分かった
  • しかし,以下の図と照らし合わせると,[-1:-4:-1]という表記では,初期値と終了値のペアが左にずれているように思える

(negative sliceの「-1」→「-4」で,-1ずつ取ると,[9,8,7]が得られそうに思える)

Python 3 Cheat Sheet
via Python 3 Cheat Sheet

ステップの起点はどうやって決まるのか?

  • チートシートを頼りにするなら,[-0:-3:-1][10,9,8]が得られれば自然な感じがしますが,これは空リストを返します([0:-3:-1]と同じになる)
  • この変な感じがする動作は実際のところ,どのような仕様になっているのでしょうか?

ドキュメントの見方が悪いのか,それっぽい記述が見つけられませんでした)

  • また,「インデックスの値でスライスし,終了値は切り捨てる」と考えれば他の動作とも整合性をもって理解できるにも関わらず,上に掲載したようなチートシートが製作されたのはなぜでしょうか?(何か意図があったのか,あるいは想定していなかったのか,本家が別にあり,それを踏襲しただけなのか...など)

尚,スライスでreverse()する方法にこだわって調べている理由は,
以下のページでスライスの実行速度が速いと紹介されていたためです

異論・補論がある場合は教えてもらえるとうれしいです



回答してくださったhayataka2049さん,quiquiさん,ありがとうございます.
なるほど,0 <= n < (j-i)/kというルールがあったのですね.まさか組み込み型のところに書いてあったとは,盲点でした!
今回は,より平易に書き下してくださったquiquiさんをベストアンサーとしたいと思います.
回答ありがとうございました!

(チートシートの謎はとりあえず保留にしておきます^^)

AnMoreNight, tachikoma👍を押しています

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

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

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

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

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

guest

回答2

0

ベストアンサー

https://docs.python.jp/3.6/library/stdtypes.html#common-sequence-operations
の注釈5.

s の「 i から j まででステップが k のスライス」は、インデックス x = i + n*k (ただし n は 0 <= n < (j-i)/k を満たす任意の整数)を持つ要素からなるシーケンスとして定義されます。
(略)
k が負の数である場合、 i または j が len(s) - 1 より大きければ len(s) - 1 を代わりに使用します。 i または j を省略または None を指定すると、 "端" (どちらの端かは k の符号に依存) の値を代わりに使用します。なお k はゼロにできないので注意してください。

と、注釈3

ただし -0 はやはり 0 であることに注意してください。

です。

まず、

>>> a = [1,2,3,4,5,6,7,8,9,10] >>> a[6:3:-1] [7, 6, 5] >>> a[3:6:-1] []

という動作を確認してください。話はそれからです。

a[6:3:-1] は i=6 j=3 k=-1 なので 0<= n < (3-6)/(-1) を満たす範囲で動きますから、0<= n < 3 なのですね。

n=0 → i + nk = 6 → a[6] → 7
n=1 → i + n
k = 5 → a[5] → 6
n=2 → i + n*k = 4 → a[4] → 5

です。

a[3:6:-1] は i=3 j=6 k=-1 なので 0 <= n < (3-6)/(-1) を満たす範囲で動かしなさいという意味ですが 0 <= n < -3 を満たすnはないので空リストなのです。


a[-0:-3:-1]a[0:7:-1]と等しく、0 <= n < (0-7)/(-1) つまり 0 <= n < -7 を範囲とするので空になります。

期待している動作をするのは a[:-4:-1] (または普通は書かないけどa[None:-4:-1])です。

a[:-4:-1]はkが負値なので、i側のは最後で、a[9:-4:-1]と等しく、jも負値なので、a[9:10-4:-1]からa[9:6:-1]と等しいです。

i=9 j=6 k=-1 なので 0 <= n < (6-9)/(-1) を満たすよう動きますから、0 <= n < 3 という範囲になり、[a[9+0*(-1)], a[9+1*(-1)], a[9+2*(-1)]]つまり[10, 9, 8]というリストを得ます。

投稿2018/08/27 11:28

編集2018/08/27 11:32
quickquip

総合スコア11038

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

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

0

4. 組み込み型 — Python 3.6.5 ドキュメント | 4.6.1. 共通のシーケンス演算

によると、

|演算|結果|注釈|

|:--|:--:|--:|
|s[i] |s の 0 から数えて i 番目の要素 |(3)|
|s[i:j] |s の i から j までのスライス |(3)(4)|
|s[i:j:k] |s の i から j まで、 k 毎のスライス |(3)(5)|

注釈:
3. i または j が負の数の場合、インデックスはシーケンスの末端からの相対インデックスになります: len(s) + i または len(s) + j が代わりに使われます。 ただし -0 はやはり 0 であることに注意してください。

4.s の i から j へのスライスは i <= k < j となるようなインデックス k を持つ要素からなるシーケンスとして定義されます。 i または j が len(s) よりも大きい場合、 len(s) を使います。 i が省略されるか None だった場合、 0 を使います。 j が省略されるか None だった場合、 len(s) を使います。 i が j 以上の場合、スライスは空のシーケンスになります。

5.s の「 i から j まででステップが k のスライス」は、インデックス x = i + nk (ただし n は 0 <= n < (j-i)/k を満たす任意の整数)を持つ要素からなるシーケンスとして定義されます。言い換えるとインデックスは i, i+k, i+2k, i+3*k と続き、 j に達したところでストップします (ただし j は含みません)。 k が正の数である場合、 i または j が len(s) より大きければ len(s) を代わりに使用します。 k が負の数である場合、 i または j が len(s) - 1 より大きければ len(s) - 1 を代わりに使用します。 i または j を省略または None を指定すると、 "端" (どちらの端かは k の符号に依存) の値を代わりに使用します。なお k はゼロにできないので注意してください。また k に None を指定すると、 1 が指定されたものとして扱われます。

まとめると、今回関係しているルールは

  • start, endに負値が与えられた場合、len(s) + iまたはlen(s) + jに機械的に変換される。
  • stepの挙動はインデックスx = i + n*k (n=0,1,2,3,..., 0 <= n < (j-i)/k)
  • i または j を省略または None を指定すると、 "端" (どちらの端かは k の符号に依存) の値を代わりに使用(kが正なら0,負ならlen(s)になると思われる)

の3つですかね。

  • [1,2,3,4,5,6,7,8,9,10][:-3:-1]について考えてみる

省略を直し、負値を変換すると[1,2,3,4,5,6,7,8,9,10][10:7:-1]となる。n<(j-i)/kよりn<3である。よって[10, 9]が得られる

投稿2018/08/27 11:37

hayataka2049

総合スコア30933

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問