Python 入門2 (文字列, リスト)

# はじめに


このシリーズは、プログラミング経験やアルゴリズムとデータ構造などの知識がある方に向けて、Pythonの基礎について解説することを目的としています。


一つの記事あたり大体１５分程度で読み終われるように文章量を調整しています。


この記事はPython入門シリーズの第２回目の投稿にあたります。


今回の記事ではタイトルにもある通り、文字列とリストについて解説します。


# 目次

- 文字列
   - 文字列の宣言
   - 値の埋め込み
   - 文字列の操作
- リスト
   - リストとは
   - リスト内包表記
   - スライス
   - range関数

# 文字列

### 文字列の宣言

```str.py
str1 = "私は"
str2 = '"犬"が好きです。'
str3 = str1 + str2   # 文字列の結合

print(str3)
```

> 私は"犬"が好きです。


Pythonでは、文字列の記述方法としてシングルクォーテーション、またはダブルクォーテーションのいずれかを用いることができます。


この二通りのやり方には基本的には違いがありません。


しかし、文字列中にシングルクォーテーションを挿入したい場合には、ダブルクォーテーションを使います。逆もまた同様に使い分けます。


Pythonでは、文字列は初期化後の変更はできないので、文字列に対して改変を伴う操作を行う場合には、新しい文字列を作成することになります。


上の例にあるstr1とstr2を結合している部分では、どちらか一方の文字列を拡張しているのではなく、結合した結果として得られる文字列を新たに生成していることになります。

Pythonには、文字列の記述方法としてシングルクォーテーションを用いる場合と、ダブルクォーテーションを用いる場合の二通りのやり方があります。

文字列中にシングルクォーテーションを挿入したい場合には、文字列中のものと文字列記述用のものが重複するので、ダブルクォーテーションを利用します。

### 値の埋め込み

Pythonでは文字列に値の埋め込みをするための方法がいくつか用意されていますが、今回は二つのやり方を解説します。

```encode_val.py
name = "レン"
age = 16

print("名前：　%s　年齢：　%d" % (name, age))   # 方法１
print("名前：　{}　年齢：　{}".format(name, age))   # 方法２
```

> 名前：　レン　年齢：　16
> 名前：　レン　年齢：　16

#### 方法１

**Step 1** 値を埋め込みたい位置を決めた後、フォーマット識別子を文字列に挿入する。

**フォーマット識別子の例**
| データ型         | フォーマット識別子 |
|:-----------------|------------------:|
| int              |              %d   | 
| float            |              %f   |
| float (精度指定)  |              %.2f|
| string           |              %s |

**Step 2** 埋め込みたい値をタプルと呼ばれるデータ構造に保存する。

**Step 3** 文字列とタプルを%でつなげる。

#### 方法２

**Step 1** 値を埋め込みたい位置を決めた後、{}を文字列に挿入する。

**Step 2** 文字列オブジェクトのformatメソッドを呼び出し、埋め込みたい値を引数として渡す。

### 文字列の操作

```str_utils.py
fruit = 'banana'
print(fruit.capitalize())      # 先頭を大文字にする
print(fruit.upper())           # すべての文字を大文字に変換する
print('APPLE'.lower())         # すべての文字を小文字に変換する
print(fruit.center(10, '-'))   # 文字列を中心に寄せる
print(fruit.rjust(10, '-'))    # 文字列を右側に寄せる
print(fruit.ljust(10, '-'))    # 文字列を左側に寄せる
print(fruit.replace('an', 'A')) # 文字列を置き換える
```

> Banana
> BANANA
> apple
> --banana--
> ----banana
> banana----
> bAAa

#### 文字列の位置を調整するメソッド
|メソッド名|　操作 |
|:-------- |-------------:|
|**center**|　 中央に寄せる|
|**rjust**|　　右側に寄せる|
|**ljust**|　　 左側に寄せる|

| 引数 | 説明 |
|:-----|:-----|
|第一引数|文字列のために確保するスペースの広さを指定します。|
|第二引数|余ったスペースを埋める文字を指定するために用います。デフォルトでは空白となっています。|

#### 文字列の置き換えを行うメソッド

**replaceメソッド**

```
str.replace(old, new, max)
```

| 引数 | 説明 |
|:-----|:-----|
|old  |必ず必要 　置き換えの対象となる文字列|
|new  |必ず必要 　置き換え後の文字列|
|max  |任意 　置き換えが複数回行われる場合、最初のmax回分だけ置き換える。|


第一引数で指定された文字列と一致する部分を第二引数で指定された文字列で置き換えます。

上の例では文字列'banana'中に含まれている全ての'an'を'A'に置き換えるという操作をしています。


# リスト

### リストとは

リストとは、Pythonで最もよく用いられるデータ構造の一つです。

リストには異なる型のデータを同時に保存することができます。また、保存されたデータの値を変更することができます。

要素には順番があり、添え字（インデックス）を使って要素にアクセスすることができます。


```ls.py
ls_num = [1, 2, 3, 4, 5]
ls_str = ["Apple", "Google", "Microsoft"]
ls_mix = [1, 4, 4.32, "Java", "C++", 94]   # 複数のデータ型を保存可能

print(ls_num)
print(ls_str)
print(ls_mix)

ls = ls_num + ls_str   # リストの結合
print(ls)
```

>[1, 2, 3, 4, 5]
>['Apple', 'Google', 'Microsoft']
>[1, 4, 4.32, 'Java', 'C++', 94]
>[1, 2, 3, 4, 5, 'Apple', 'Google', 'Microsoft']


```ls_utils.py
ls_num.append(44.303)   # リストに新しい値を追加
print(ls_num)
print(ls_num[-1])       # 添え字-1は、一番後ろの要素に対応する
tail = ls_num.pop()     # リストの一番後ろの要素の値を取り出す
print(ls_num)           # 要素44.303はpopメソッドによって既に削除されている
```

> [1, 2, 3, 4, 5, 44.303]
> 44.303
> [1, 2, 3, 4, 5]

Pythonでは、一般的な０以上の整数の添え字だけではなく、負の整数値を持つ添え字（インデックス）を指定することもできます。

負の添え字を用いることで、リストの一番後ろの要素を基準(-1)にして、リストの先頭に向かって値を小さくしていく(-1, -2, -3, ...)ことで逆順に要素を指定することができます。

-1は一番後ろの要素に対応し、-2は2番目に後ろにある要素に対応します。


### リスト内包表記

```
[式 for 任意の変数名 in イテラブルオブジェクト]
# イテラブルオブジェクトとは、配列やリストのような繰り返しの処理によって順番に要素を取り出すことができるオブジェクトのことを言います。
```

リスト内包表記の目的は、イテラブルオブジェクトの各要素に対して特定の処理を繰り返した後、結果を新規のリストに保存するという一連の作業を簡潔に記述することにあります。

```ls_comprehensions_num.py
num = [1, 2, 3, 4, 5]
squared_num = [n ** 2 for n in num]   # リストnumの各要素を二乗した結果を新規のリストに保存する
print(squared_num)
```

実行結果
> [1, 4, 9, 16, 25]

```ls_comprehensions_str.py
ls_str = ["I", "like", "Okinawa", "HELLO"]
ls_lower = [str.lower() for str in ls_str]   # lower関数を使って大文字を小文字に変換

print(ls_str)   # 変換前
print(ls_lower)   # 変換後 (大文字 -> 小文字)
```
実行結果
>['I', 'like', 'Okinawa', 'HELLO']
>['i', 'like', 'okinawa', 'hello']

また、リスト内包表記では、イテラブルオブジェクトの全ての要素に対して無条件に処理を行う代わりに、if文で指定された条件を満たす要素だけを対象とすることもできます。

この場合、下記のような表記方法を用いることができます。

```
[式 for 任意の変数名 in イテラブルオブジェクト if 条件式]
```

```ls_comprehensions_if.py
num = [1, 3, -3, -4, 5, 10]
squared_plusnum = [n ** 2 for n in num if n > 0]   # n > 0 の要素だけが二乗され、新規のリストに保存される
print(squared_plus_num)
```

実行結果
> [1, 9, 25, 100]

numの要素nが正の整数のとき真となる条件式を付け加えた結果、numに含まれる全ての正の整数のみを二乗して得られるリストを作成することができました。

### スライス

リストでは個々の要素を添え字を使って取得できます。それに加えて、スライスと呼ばれる機能を用いるとリストのサブリスト（一部分）を取得することができます。

```slice.py
# range関数を用いて０以上１０未満の整数列を生成
# ただし、生成されるものはrange型オブジェクトなので、listへの変換が必要
ls = list(range(10)) 

print(ls)
print(ls[3:7])    # 添え字3から6までのサブリストを取得
print(ls[:8])     # 添え字0から7までのサブリストを取得
print(ls[2:])     # 添え字2から最後の要素までのサブリストを取得
print(ls[:-1])    # 先頭から最後から一つ前までのサブリストを取得
print(ls[:])      # 全ての要素を含むサブリストを取得 
```

> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
> [3, 4, 5, 6]
> [0, 1, 2, 3, 4, 5, 6, 7]
> [2, 3, 4, 5, 6, 7, 8, 9]
> [0, 1, 2, 3, 4, 5, 6, 7, 8]
> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

スライスする範囲は以下のように指定することができます。

```
リスト名[始点:終点]
```

始点を省略した場合には、リストの先端からスライスされることになります。

また、終点を省略した場合には、リストの末端までスライスされることになります。

注意しなければならないのは、終点の指定に用いた添え字は生成されるサブリストには含まれないことです。

### range関数

先程の例で見たようにrange関数を用いると数列(rangeオブジェクト)を作成することができます。

```
range(start, stop, step)
```

|引数|説明|
|---------:|:---------------------------------------|
|start     | 任意 　開始位置を指定する。デフォルトでは0に設定されている。|
|stop      | 必ず必要　停止位置を指定する。　ただし、stopの値自体が数列に含まれることはない。 |
|step      | 任意 　数列の項差を指定する。デフォルトでは１に設定されている。|

range関数の使い道の一つとして、N回繰り返すforループを記述するために用いることがあります。

この場合、range関数で0からN-1までの数列（rangeオブジェクト）を作成し、その数列に対してループを行うという仕組みになります。

```range.py
x = range(5)   # 0から4までのrangeオブジェクトを作成
for i in x:    # 0から4まで5回分ループ
    print(i ** 3)
```

> 0
> 1
> 8
> 27
> 64


# 参考文献
[Pythonチュートリアル (英語版)](https://colab.research.google.com/github/cs231n/cs231n.github.io/blob/master/python-colab.ipynb)

[リストの基本](https://atmarkit.itmedia.co.jp/ait/articles/1905/31/news015.html)

[リスト内包表記](https://www.javadrive.jp/python/list/index16.html)

[range関数 (英語版)](https://www.w3schools.com/python/ref_func_range.asp)

[replaceメソッド（英語版）](https://www.w3schools.com/python/ref_string_replace.asp)