nishiyamasuの日記

忘れやすいので、メモ。。。

Pythonで整数のリストから重複(出現回数)を調べる

お題として、整数から成るリストの中から重複(出現回数)を調べます。

例としては、次のようになります。

調べる対象のリスト: 
 [3, 9, 2, 2, 2, 7, 8, 8]

期待する結果:                        
 3 -> 1回                       
 9 -> 1回                       
 2 -> 3回                       
 7 -> 1回                       
 8 -> 2回

このお題を解くPythonプログラムを考えます。

先にプログラムを示したいと思います。

def count_duplicate(array):
    duplicate = {}
    for i in array:
        if i in duplicate:
            duplicate[i] += 1
        else:
            duplicate[i] = 1
    return duplicate


x = [3, 9, 2, 2, 2, 7, 8, 8]

duplicate_map = count_duplicate(x)

for k in duplicate_map.keys():
    print(k, duplicate_map[k])

このプログラムの鍵となるところは、関数count_duplicateです。

count_duplicateは、引数に調べる対象のリストを取り、調べた結果を格納するディクショナリduplicateを返します。duplicateは、キーにリスト中の整数、バリューに整数の出現回数を持ちます。

関数count_duplicateの中の処理としては次のようになります。

調べる対象のリストについて、for文のループを回す。
↓
duplicateに
・対象の整数がある場合、出現回数を+1する。
・対象の整数がない場合、出現回数を1にする。

count_duplicateの実行し終えた時点で、お題を解くことはほぼ終わっています。

あとは結果を出力します。
結果のディクショナリからキー、バリューをすべて取得します。次の部分です。

for k in duplicate_map.keys():
    print(k, duplicate_map[k])

duplicate_map.keys()ですべてのキーを取得して、for文の中で、duplicate_map[k]でバリューにアクセスしprintで出力します。

実行結果は次のようになります。 各行について、
・左の値:整数
・右の値:出現回数
になります。

3 1
9 1
2 3
7 1
8 2

予想通りに結果を得られました。

pythonでリストから要素を探す

整数だけから成るリストから、1つの整数を探し出し、インデックス(何番目にあるか)を求めます。

例題としては、次のようになります。

リスト:[ 3, 1, 0, 5, 11, 4, 7, 2 ]
探す整数:5

求めるインデックス:3

1つのやり方として、for文で最初から最後まで要素を探して、対象の整数と一致したときにそのインデックスが答えになるという方法があります。単純ですが分かりやすいです。

def find(array, target):
    for i in range(len(array)):
        if array[i] == target:
            return i
    return -1

print(find([3, 1, 0, 5, 11, 4, 7, 2], 5))

上のコードについて、findという関数が実際にインデックスを求めます。 引数に、リストと、探す対象の整数を指定します。対象の整数が存在しなかった場合、-1を返します。

実行結果は次のようになります。

3

リストの長さをnとすると、最大でn回の探索が発生します。

Goで時間の出力形式を日本の形式にする。

Goの構造体のjson出力フォーマットを自分で決めたいことがあった。

Goでは、普通にやると次のように時間が出力される。

package main

import (
    "fmt"
    "time"
)

func main() {
    now := time.Now()
    fmt.Println(now)
}

// main実行結果
// 2019-01-06 22:27:31.043934843 +0900 JST m=+0.000154895

見てわかるのは、とても分かりにくいということ。 日本人なので、やはり○○年○月○日の形式で出力してほしい。

Goのtime.Time型にあるFormatメソッドにより、時間の出力形式を変更できる。

package main

import (
    "fmt"
    "time"
)

func main() {
    now := time.Now()
    fmt.Println(now.Format("2006年01月02日"))
}

// main実行結果
// 2019年01月06日

Goのstructにtime.Time型のフィールドがある場合を考える。

type Data struct {
    ID        int
    CreatedAt time.Time
}

CreatedAtがtime.Time型のフィールド。

このstructをjson.MarshalIndentを使って出力する。 structをjson出力すると、CreatedAtの値はデフォルトの形式で出力されてしまう。

package main

import (
    "encoding/json"
    "fmt"
    "time"
)

type Data struct {
    ID        int
    CreatedAt time.Time
}

func main() {
    data := Data{
        ID:        1,
        CreatedAt: time.Now(),
    }
    // ignoring err..
    b, _ := json.MarshalIndent(data, "", "  ")
    fmt.Println(string(b))
}

// main実行結果
// {
//   "ID": 1,
//   "CreatedAt": "2019-01-06T23:10:03.455595285+09:00"
// }

CreatedAtの時間の出力を日本の形式に変更する。それには、time.Timeの代わりに新しくstructを用意して、MarshallJSON()メソッドを自分で実装する。
新しく用意したstrcutをCreatedAtに使用する。

package main

import (
    "encoding/json"
    "fmt"
    "time"
)

type Data struct {
    ID        int
    CreatedAt JSONTime
}

type JSONTime time.Time

func (t JSONTime) MarshalJSON() ([]byte, error) {
    stamp := fmt.Sprintf("\"%s\"", time.Time(t).Format("2006年01月02日"))
    return []byte(stamp), nil
}

func main() {
    data := Data{
        ID:        1,
        CreatedAt: JSONTime(time.Now()),
    }
    // ignoring err..
    b, _ := json.MarshalIndent(data, "", "  ")
    fmt.Println(string(b))
}

// 実行結果
// {
//   "ID": 1,
//   "CreatedAt": "2019年01月06日"
// }

これで、CreatedAtの値が日本の時間形式で表示されるようになった。