1. okkn
Changes in title
-[python] スライスでリバース!!
+[python] スライスでリバース!!(スライスの解説もあるよ!)
Changes in body
Source | HTML | Preview
@@ -1,105 +1,168 @@
スライスに関して自分の中では新しい発見だったので備忘録。
-基本はいいよって人は[7割スキップ](#%E3%81%8A%E5%BE%85%E3%81%A1%E3%81%8B%E3%81%AD%E3%82%B9%E3%83%A9%E3%82%A4%E3%82%B9%E3%81%A7%E3%83%AA%E3%83%90%E3%83%BC%E3%82%B9)ww!
+基本はいいよって人は[8割スキップ](#%E3%81%8A%E5%BE%85%E3%81%A1%E3%81%8B%E3%81%AD%E3%82%B9%E3%83%A9%E3%82%A4%E3%82%B9%E3%81%A7%E3%83%AA%E3%83%90%E3%83%BC%E3%82%B9)ww!
-##スライスの基本の基本の基本!!
-皆さんもリスト型やら文字列から要素を取り出す際にスライスして取り出すことあると思います。
-スライス?なにそれ?おいしいの?っていう人のためにもさらっと使い方を書き出してみましょう。
+##スライスの基本!!
+皆さんもリスト型やら文字列から要素を取り出す際にスライスして取り出すことあると思います。
+スライス?なにそれ?おいしいの?っていう人のためにも使い方を解説しておきましょう。
###準備
スライスじゃないですね(;^ω^)
```py
-a = [1, 2, 3, 4, 5, 6, 7, 8, 9] # 2系でも3系でも問題ないようにrangeは敢えて使いません
-a[2] #3
+a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 2系でも3系でも問題ないようにrangeは敢えて使いません
+a[2] #2
```
###普通にスライス
```py
-# n番目からm-1番目の要素を取り出す
-a[n:m]
-# 1番目から3番目の要素を取り出す
-a[1:4] #[2, 3, 4]
+# i番目からj-1番目の要素を取り出す
+a[i:j]
+# 2番目から7(8-1)番目の要素を取り出す
+a[2:8] #[2, 3, 4, 5, 6, 7]
# 始点を省略すると0番目から
-a[:3] #[1, 2, 3]
-# 終点を省略すると最後まで
-a[7:] #[8, 9]
+a[:6] #[0, 1, 2, 3, 4, 5]
+# 終点を省略すると要素の一番最後まで
+a[7:] #[7, 8, 9]
```
###後ろからスライス
-負の数にすると後ろから数えてくれ
+負の数にすると後ろから数えてくれます
```py
-# -1で一番最後
+# [-1]で要素の一番最後
a[-1] #9
-# ひねくれ者かな?
+# -8番目から-6(-5-1)番目の要素を取り出す
a[-8:-5] #[2, 3, 4] (使わない)
# 始点省略
-a[:-6] #[1, 2, 3] (ほぼ使わない)
+a[:-6] #[0, 1, 2, 3] (ほぼ使わない)
# 終点省略
a[-2:] #[8, 9] (拡張子の取り出しなどよく使う)
```
+「i番目からj-1番目の要素を取り出す」という決まりごとは変わらないので、以下の例も可能です。
+
+```py
+# 2番目から-6(-5-1)番目の要素を取り出す
+a[2:-5] #[2, 3, 4]
+# -8番目から5(6-1)番目の要素を取り出す
+a[-8:6] #[2, 3, 4, 5]
+```
+
スライスの概念を一番わかりやすく解説しているのはやはり[PythonWeb](http://www.pythonweb.jp/tutorial/string/index11.html)ですね。
-##一歩踏み込んでスライス!
+
+##一歩踏み込んでスライス!
前提として一歩踏み込んだスライスの使い方を紹介!
知らない人は意外といるかも?
ここからは私は知りませんでした。
###ステップスライス(勝手に名づけた)
本当の名前があるのならば教えていただければ幸いです。
```py
-# コロンを2個続けるとステップして抜き出します
-a[::3] #[1, 4, 7]
-# もちろん切り出しつつのステップも可能
-a[2:7:3] #[3, 6]
-
+# i番目からj-1番目の要素をk個ごとに取り出す
+# (ただし、定数 c は 0 <= c < (j-i)/k を満たす最大の整数)
+a[i:j:k] #[a[i], a[i+1*x], a[i+2*x], ..., a[i+c*x]]
+# 全体から要素を3個ごとに取り出す
+a[::3] #[0, 3, 6, 9]
+# 切り出しながら要素を2個ごとに取り出す
+a[2:8:2] #[2, 4, 6]
+```
+
+ステップ値(`a[::k←こいつ]`)が正の整数の場合、切り出した要素を元にしてステップする(と考えると良いです)。
+ちなみに、**ステップ値に【0】は指定できません**。
+
+当然始点や終点の値を省略してのステップスライスも可能です。
+
+```py
+# 始点から5(6-1)番目の要素を2個ごとに取り出す
+a[:6:2] #[0, 2, 4]
+# 7番目から終点までの要素を2個ごとに取り出す
+a[7::2] #[7, 9]
+```
+
+###後ろからステップスライス
+ステップ値を負の数にすると**逆順(←重要)**にしてステップして取り出してくれます。
+
+```py
+
# 負の数を使って後ろから
-a[::-3] #[9, 6, 3]
-# ややこしい・・・orz
-a[-2:-8:-3] # [8, 5]
-# コロンが2個あって且つ後ろからステップする場合は逆順にしてから抜き出してるっぽい
-# よって以下は何も取り出せない
-a[-8:-2:-3] # []
+a[::-3] #[9, 6, 3, 0]
+```
+ステップ値を負の整数にする場合は、基本的にこの使い方のみで使ったほうが良い気がします(理由は後述)。
-# cf. a[-8:-5] -> [2, 3, 4]
+###ステップスライスの応用
+※この項は本筋とは関係ないので飛ばしても問題ありません。
+ステップ値を負の整数にしてスライスする場合、以下の使い方は難しいと思います。
+そのため、コードレビューや後で見返した際に何をしているのかが分かりづらいといった理由で使わないほうが良いかもしれません。
+
+```py
+# 7番目から始点までの要素を-2個ごとに取り出す
+a[7::-2] # [7, 5, 3, 1]
+# 終点から5番目までの要素を-2個ごとに取り出す
+a[:4:-2] # [9, 7, 5]
+# 8番目から3番目までの要素を-2個ごとに取り出す
+a[8:2:-2] # [8, 6, 4]
+# -2番目から-7番目までの要素を-3個ごとに取り出す
+a[-2:-8:-3] # [8, 5]
+
```
+実はこの場合(ステップ値が負の整数の場合)のみ概念的には「i番目から**j+1**番目の要素をk個ごとに取り出す」となります。
+(スライスの全てにおいて、iまたはjの値が省略された場合は上記の決まりごとには当てはまりません。)
+また、他の場合とは違い **i > j** の関係になることも注意が必要です。
+
+先程重要と書いた**逆順になる**ということを思い出してください。
+k < 0 の場合はi、jについても大小関係が反転すると考えると良さそうです。
+(数学で言うところの辺々の正負を逆転させると、大小関係が逆転するようなイメージが近いかもしれません。)
+
+
+
##お待ちかね!スライスでリバース!!
一応経緯。
どうでもいいが[ここ](http://nlab.itmedia.co.jp/nl/articles/1505/10/news014.html)を見てpython使ったら反対から読む文章の作成とか楽勝だろと思い3分クッキングの感覚で入力。
(画像の**!すまし錨抜 アュギィフムアミレプ ぜかまし×たなこ**の話)
```py
from __future__ import print_function
konata = 'こなた×しまかぜ プレミアムフィギュア 抜錨します!'
print(''.join(reversed(konata)))
# !すまし錨抜 アュギィフムアミレプ ぜかまし×たなこ
```
でも残念ながらこの方法は一度`reversed(konata)`の部分でオブジェクトを生成しちゃってますのでなんか気に入りません。
もっとスマートに!!
と思い色々探していたらありました!!
おなじみ、stack overflow
-[Best way to create a “reversed” list in Python?](http://stackoverflow.com/questions/3705670/best-way-to-create-a-reversed-list-in-python)
+[Best way to create a “reversed” list in Python?](https://stackoverflow.com/questions/3705670/best-way-to-create-a-reversed-list-in-python)
上から順に読んできた方はもうお気づきですね。
以下になります。
```py
print(konata[::-1])
# 変態記法:print(konata[-1:0 - len(konata):-1])
# !すまし錨抜 アュギィフムアミレプ ぜかまし×たなこ
```
**Very very very very SMART!!**
興奮しすぎですね。
しかも上記リンクを読んだらわかるとおり速いらしいです。(私は未検証)
そういう点においても**SMART**ですね。
##まとめ
**逆順にしたけりゃ`[リストor文字列][::-1]`にしとけ!!**
+
+###【おまけ】スライスの定理(?)
+`[リストor文字列][i:j:k]`についてステップ値 k が無指定の場合は k = 1 であると定義する(仕様より)。
+その時以下が成り立つ。
+
+1. k > 0 のとき「 i 番目から j - 1 番目の要素を k 個ごとに取り出す(i < j)」
+2. k < 0 のとき「 i 番目から j + 1 番目の要素を k 個ごとに取り出す(i > j)」
+
+ただし、i または j の値が省略されたときは不成立。
+
+##参照
+[4章 組み込み型 - 4.6.1 共通のシーケンス演算](https://docs.python.org/ja/3.6/library/stdtypes.html?highlight=%E3%83%AA%E3%82%B9%E3%83%88#common-sequence-operations)