Pythonのリスト、タプル、辞書

今回は、Pythonのデータ型のうちリスト、タプル、辞書を説明します。
久しぶりのPythonの説明です。Javaの宣言方法、メソッドと比較します。

#リスト
複数の要素を順番を維持して各要素の集合を表現するデータ型です。
[]で囲んで宣言します。宣言時に要素を設定する場合は、[]の中にカンマ区切りで要素を宣言します。

##各要素にアクセス
各要素は、インデックスでアクセス可能で、長さnのリストaのインデックスは0..n-1となっており、
m番目（1<= m <= n）の要素は、a[m - 1]で取得可能です。

```py:Python
    a = ["1-1", "1-2", "1-3", "1-4", "1-5"]
    print(a[1]) # ⇒ 1-2
```

Javaでも同じようにm番目（1<= m <= n）の要素は、a.get(m - 1)で取得可能です。

```java:Java
    List<String> a = new ArrayList<String>(Arrays.asList(new String[]{"1-1", "1-2", "1-3", "1-4", "1-5"}));
    System.out.println(a.get(1)); // ⇒ 1-2;
```

##サイズ取得
リストのサイズを得るには、len関数を使用します。

```py:Python
    a = ["1-1", "1-2", "1-3", "1-4", "1-5"]
    print(len(a)) # ⇒ 5
```

Javaではsizeメソッドを利用しますね。

```java:Java
    List<String> a = new ArrayList<String>(Arrays.asList(new String[]{"1-1", "1-2", "1-3", "1-4", "1-5"}));
    System.out.println(a.size()); // ⇒ 5
```

##リストの結合
pythonでのリスト同士の結合は、 + 演算子を使用します。
この関数は、リスト同士を結合して新しいリストを作成します。
そのため元のリストには影響を与えません。

```py:Python
    a = ["1-1", "1-2", "1-3", "1-4", "1-5"]
    b = ["2-1", "2-2", "2-3", "2-4", "2-5"]
    print(a + b) # ⇒ ['1-1', '1-2', '1-3', '1-4', '1-5', '2-1', '2-2', '2-3', '2-4', '2-5']
    print(a) # ⇒ ['1-1', '1-2', '1-3', '1-4', '1-5']
    print(b) # ⇒ ['2-1', '2-2', '2-3', '2-4', '2-5']
```

Javaでは、あまり良い方法はないみたいですね。
新しいリストにaとbの各要素をすべて追加するしかないようです。

```java:Java
    List<String> a = new ArrayList<String>(Arrays.asList(new String[]{"1-1", "1-2", "1-3", "1-4", "1-5"}));
    List<String> b = new ArrayList<String>(Arrays.asList(new String[]{"2-1", "2-2", "2-3", "2-4", "2-5"}));
    List<String> c = new ArrayList<String>();
    c.addAll(a);
    c.addAll(b);
    System.out.println(c); // ⇒ [1-1, 1-2, 1-3, 1-4, 1-5, 2-1, 2-2, 2-3, 2-4, 2-5]
```

##リストに要素を追加する
リストに要素を加えるには、要素を一つ追加すると１つのリストをまるまるもう一つのリストに加えるの二つの方法があります。
まず、要素を一つ追加するには、appendやinsertメソッドを利用します。
appendはリストの最後に要素を追加します。insertは、指定したインデックスの位置に要素を追加します。

```py:Python
    a = ["1-1", "1-2", "1-3", "1-4", "1-5"]
    # リストの最後に追加します。
    a.append("1-7")
    print(a) # ⇒ ['1-1', '1-2', '1-3', '1-4', '1-5', '1-7']
    # 指定したインデックスの箇所に追加します。
    a.insert(5, "1-6")
    print(a) # ⇒ ['1-1', '1-2', '1-3', '1-4', '1-5', '1-6', '1-7']
```

Javaでは、両方ともaddメソッドを利用します。

```java:Java
    List<String> a = new ArrayList<String>(Arrays.asList(new String[]{"1-1", "1-2", "1-3", "1-4", "1-5"}));
    a.add("1-7");
    System.out.println(a); // ⇒ [1-1, 1-2, 1-3, 1-4, 1-5, 1-7]
    a.add(5, "1-6");
    System.out.println(a); // ⇒ [1-1, 1-2, 1-3, 1-4, 1-5, 1-6, 1-7]
```

次に１つのリストをまるまるもう一つのリストに追加する方法です。
extendメソッドを利用します。引数にリストを指定することでそのリストの要素をすべて追加できます。

```py:Python
    a = ["1-1", "1-2", "1-3", "1-4", "1-5"]
    b = ["2-1", "2-2", "2-3", "2-4", "2-5"]
    a.extend(b)
    print(a) # ⇒ ['1-1', '1-2', '1-3', '1-4', '1-5', '2-1', '2-2', '2-3', '2-4', '2-5']
```

Javaではすでに書きましたが、addAllメソッドを使用することで追加できます。

```java:Java
    List<String> a = new ArrayList<String>(Arrays.asList(new String[]{"1-1", "1-2", "1-3", "1-4", "1-5"}));
    List<String> b = new ArrayList<String>(Arrays.asList(new String[]{"2-1", "2-2", "2-3", "2-4", "2-5"}));
    a.addAll(b);
    System.out.println(a); // ⇒ [1-1, 1-2, 1-3, 1-4, 1-5, 2-1, 2-2, 2-3, 2-4, 2-5]
```

##要素が含まれるか
ある要素がリスト内に存在するか確認するには「in」を使用します。
存在する場合は、True、存在しない場合は、Falseが返却されます。

```py:Python
    a = ["1-1", "1-2", "1-3", "1-4", "1-5", ["1-2", "1-3"]]
    print("1-2" in a) # ⇒ True
    print("1-6" in a) # ⇒ False
    #以下のようにリストがリスト内に存在するかもチェックできます。
    print(["1-2", "1-3"] in a) # ⇒ True
```

Javaではcontainsメソッドを利用します。

```java:Java
    a = new ArrayList<String>(Arrays.asList(new String[]{"1-1", "1-2", "1-3", "1-4", "1-5"}));
    System.out.println(a.contains("1-2")); // ⇒ true
    System.out.println(a.contains("1-6")); // ⇒ false
```

##要素の切り出し
要素を切出すには、文字列と同じように[n:m]の形式で指定します。

```py:Python
    a = ["1-1", "1-2", "1-3", "1-4", "1-5"]
    #インデックス2からインデックス4まで（4は含まない）
    print(a[2:4]) # ⇒ ['1-3', '1-4']
    #インデックス2から最後まで
    print(a[2:]) # ⇒ ['1-3', '1-4', '1-5']
    #インデックス4まで（4は含まない）
    print(a[:4]) # ⇒ ['1-1', '1-2', '1-3', '1-4']
    #2つおきに取得
    print(a[::2]) # ⇒ ['1-1', '1-3', '1-5']
```

JavaではsubListメソッドを利用します。
引数は、切取り開始インデックス、終了インデックス（含まれない）です。

```java:Java
    List<String> a = new ArrayList<String>(Arrays.asList(new String[]{"1-1", "1-2", "1-3", "1-4", "1-5"}));
    // インデックス2からインデックス4まで（4は含まない）
    System.out.println(a.subList(2, 4)); // ⇒ [1-3, 1-4]
    // インデックス2から最後まで
    System.out.println(a.subList(2, a.size())); // ⇒ [1-3, 1-4, 1-5]
    // インデックス4まで（4は含まない）
    System.out.println(a.subList(0, 4)); // ⇒ [1-1, 1-2, 1-3, 1-4]
    // 2つおきに取得は、StreamでFilterをかけないと無理かと
```


#タプル
次はタプルを説明します。タプルは、内容を変更できないリストです。
そのため、タプルないの要素を変更するようなメソッドを使用するとエラーとなります。
変更しない限りエラーとはなりません。
また、タプル自体をリストに追加することは可能です。

```py:Python
    a = ("1-1", "1-2", "1-3", "1-4", "1-5")
    a.append("1-6") # ⇒ AttributeError: 'tuple' object has no attribute 'append'
    c = ["1-1"];
    c.extend(a)
    print(c) # ⇒ ['1-1', '1-1', '1-2', '1-3', '1-4', '1-5']
```

Javaでは変更不能なリストは、Collections.unmodifiableListを利用すると作成可能です。
もちろん自分でクラスを作成しても良いです。
Collectionsクラスにはほかにも変更不能なMapの作成もでますので、時間があれば見てもよいと思います。

```java:Java
    List<String> a = new ArrayList<String>(Arrays.asList(new String[]{"1-1", "1-2", "1-3", "1-4", "1-5"}));
    List<String> unmodifList = Collections.unmodifiableList(a);
    unmodifList.add("1-1"); // ⇒ UnsupportedOperationException
```

#辞書
リストと同じようにコレクション型ですが、リストとは異なり順序は持ちません。
そのかわり、キー（key）と対応する値（value）で値を管理します。宣言方法は、波かっこ（{}）で囲い、keyとvalueをコロン（:）で区切って宣言します。次の値を宣言するには、カンマ（,）で区切ります。

```py:Python
    a = {"key" : "value", "A" : "13歳", "B" : "15歳"}
    print(a) # ⇒ {'key': 'value', 'A': '13歳', 'B': '15歳'}
```

Javaではマップですね。JavaのMapには初期値を設定する方法がありません。

```java:Java
    Map<String, String> map = new HashMap<String, String>();
    System.out.println(map); // ⇒{}
```

##要素の追加
辞書型に要素を追加するメソッドはありません。
辞書型の変数に対して、直接キー、値を指定して追加します。

```py:Python
    a = {"key" : "value", "A" : "13歳", "B" : "15歳"}
    a["C"] = "16歳"
    print(a)  # ⇒ {'key': 'value', 'A': '13歳', 'B': '15歳', 'C': '16歳'}
```

javaではputメソッドを使用します。

```java:Java
    Map<String, String> map = new HashMap<String, String>();
    map.put("A", "13歳");
    map.put("B", "15歳");
    map.put("C", "16歳");
    System.out.println(map); // ⇒{A=13歳, B=15歳, C=16歳}
```

##キーが存在するか
辞書型の変数にキーが存在するか確認するには「in」を使用します。

```py:Python
    a = {"key" : "value", "A" : "13歳", "B" : "15歳"}
    print("A" in a)  # ⇒ True
    print("C" in a)  # ⇒ False
```

JavaではcontainsKeyメソッドを使用します。
キー以外でもValueに含まれるかどうか確認できるcontainsValueメソッドもあります。
pythonにはcontainsValueに対応するメソッドはなさそうです。

```java:Java
    Map<String, String> map = new HashMap<String, String>();
    map.put("A", "13歳");
    map.put("B", "15歳");
    System.out.println(map.containsKey("A")); // ⇒ true
    System.out.println(map.containsKey("C")); // ⇒ false
    System.out.println(map.containsValue("15歳")); // ⇒ true
    System.out.println(map.containsValue("16歳")); // ⇒ false
```

##値の取得
値の取得にはgetメソッドを使用します。
getメソッドはキーを指定してValue値を取得します。もし、キーが存在しない場合Noneが返却されます。
キーが存在しない場合、Noneが返却されると困るときもあると思います。
その場合は、getの第二引数にデフォルト値を設定します。すると、キー値が存在場合、指定したデフォルト値を返します。

```py:Python
    a = {"key" : "value", "A" : "13歳", "B" : "15歳"}
    print(a.get("A"))  # ⇒ 13歳
    print(a.get("C"))  # ⇒ None
    print(a.get("A", "10歳"))  # ⇒ 13歳
    print(a.get("C", "10歳"))  # ⇒ 10歳
```

Javaでもキーに対応する値を取得するために、getメソッドを利用します。
また、デフォルト値を設定して取得したい場合は、getOrDefaultメソッドを利用します。
使用方法はpythonのデフォルト値を指定する場合と同じです。このメソッドはJava8から追加されました。
地味にありがたいです。

```java:Java
    Map<String, String> map = new HashMap<String, String>();
    map.put("A", "13歳");
    map.put("B", "15歳");
    System.out.println(map.get("A")); // ⇒ 13歳
    System.out.println(map.get("C")); // ⇒ null
    System.out.println(map.getOrDefault("A", "10歳")); // ⇒ 13歳
    System.out.println(map.getOrDefault("C", "10歳")); // ⇒ null
```

##全キーの取得
辞書に登録した全キーを取得したい場合は、keysメソッドを利用します。
登録したキーをリスト形式で返却してくれます。ただし、順番は保証されていません。
と思いましたが、dict_keysというクラスが返却されました。これを利用するには、for文を使用しないといけません。

```py:Python
    a = {"A" : "13歳", "B" : "15歳"}
    print(a.keys())  # ⇒ dict_keys(['A', 'B'])
    for key in a.keys():
        print(key)# ⇒ 'A'と'B'
```

javaでは、keySetメソッドを使用します。
このメソッドは、Setクラスでキーセットを返却します。

```java:Java
    Map<String, String> map = new HashMap<String, String>();
    map.put("A", "13歳");
    map.put("B", "15歳");
    System.out.println(map.keySet()); // ⇒ [A, B]
    for (String s : map.keySet()) {
        System.out.println(s); // ⇒ A, B
    }
```

##全値の取得
辞書に登録した値を取得したい場合は、valuesメソッドを利用します。
dict_valuesというクラスが返却されます。これを利用するには、for文を使用しないといけません。

```py:Python
    a = {"A" : "13歳", "B" : "15歳"}
    print(a.values())  # ⇒ dict_values(['13歳', '15歳'])
    for value in a.values():
        print(value) # ⇒ '13歳'と'15歳'
```

javaでは、keySetメソッドを使用します。
このメソッドは、Setクラスでキーセットを返却します。

```java:Java
    Map<String, String> map = new HashMap<String, String>();
    map.put("A", "13歳");
    map.put("B", "15歳");
    System.out.println(map.values()); // ⇒ [13歳, 15歳]
    for (String s : map.values()) {
        System.out.println(s); // ⇒ 13歳, 15歳
    }
```

##全キー、値の取得
辞書に登録したキー、値を取得したい場合は、itemsメソッドを利用します。
dict_itemsというクラスが返却されます。これを利用するには、for文を使用しないといけません。

```py:Python
    a = {"A" : "13歳", "B" : "15歳"}
    print(a.items())  # ⇒ dict_items([('A', '13歳'), ('B', '15歳')])
    for key, value in a.items():
        print(key, value) # ⇒ A 13歳, B 15歳
```

javaでは、entrySetメソッドを使用します。
このメソッドは、Setクラスでキーと値のEntryを返却します。

```java:Java
    Map<String, String> map = new HashMap<String, String>();
    map.put("A", "13歳");
    map.put("B", "15歳");
    System.out.println(map.entrySet()); // ⇒ [A=13歳, B=15歳]
    for (Entry<String, String> e : map.entrySet()) {
        System.out.println(e.getKey()); // ⇒ A, B
        System.out.println(e.getValue()); // ⇒ 13歳, 15歳
    }
```

##辞書補足
values(), keys(), items()それぞれ返却しているオブジェクトはビューオブジェクトというものらしいです。ビューオブジェクトは、辞書の項目の動的なビューを提供してもとの辞書の値が変更されるとビューの値も変更されるようです。

```py:Python
a = {"A" : "13歳", "B" : "15歳"}
items = a.items()
print(items) # ⇒ dict_items([('A', '13歳'), ('B', '15歳')])
# 要素を追加したら、ビューオブジェクトの要素も増える
a["C"] = "16歳"
print(items) # ⇒ dict_items([('A', '13歳'), ('B', '15歳'), ('C', '16歳')])
# 要素を削除したら、ビューオブジェクトの要素も消える
a.pop("A")
print(items) # ⇒ dict_items([('B', '15歳'), ('C', '16歳')])
# 要素を変更したら、ビューオブジェクトの要素も変更される
a["B"] = "14歳"
print(items) # ⇒ dict_items([('B', '14歳'), ('C', '16歳')])
```
以上です。全体的にPythonの方が簡単に書けるように思います。