- 投稿日:2020-11-21T20:29:20+09:00
golangのos/execでMakefileのmakeコマンドを実行しようとすると2回目以降の実行がエラーになる
- 投稿日:2020-11-21T07:41:18+09:00
GO gorm DB作成 INSERT JSONUnmarshal Mysql
こんにちは! GO学習中です!
今回はgormでinsertしてみたいと思います!
データは前回getしたapi
のデータを使用します。DB自体をGOから作成した記事はこちらです。
では始めていきたいと思います。
mysql.go
// root/app/models/fgi.go package mysql import ( "database/sql" _ "github.com/go-sql-driver/mysql" "github.com/jinzhu/gorm" ) // SQLConnect DB接続 func SQLConnect() (database *gorm.DB, err error) { DBMS := "mysql" USER := "root" PASS := "" PROTOCOL := "tcp(localhost:3306)" DBNAME := "テーブル名" CONNECT := USER + ":" + PASS + "@" + PROTOCOL + "/" + DBNAME + "?charset=utf8&parseTime=true&loc=Asia%2FTokyo" return gorm.Open(DBMS, CONNECT) }ここではDBはすでに作成しているものとします。
gormとはGOのORMパッケージです。SQLConnect()の関数ではDBの情報を宣言して、
return gorm.Open(DBMS, CONNECT)
とすることでdbと接続しています。
DB情報はConfigなどにまとめたほうが良いかもしれません。今回はルートユーザーで行なっていきます。fgi/fgi.go
こちらは冒頭紹介した記事
でgetしているapiのファイルです。上記の記事ではgetしただけでしたが、こちらでは
json.Unmarshalをすることで、用意した構造体に格納しています。構造体はこちらの json-to-go
というサイトで簡単に用意できます。左側にapiのjsonを貼り付けるとコード内のstructを用意してくれます。
package fgi import ( "encoding/json" "io/ioutil" "log" "net/http" ) // APIClientFgi api情報格納 type APIClientFgi struct { key string host string httpClient *http.Client } // New struct生成 func New(key, host string) *APIClientFgi { fgiClient := &APIClientFgi{key, host, &http.Client{}} return fgiClient } // StructFgi fgi格納 type StructFgi struct { Fgi struct { Current struct { Value int `json:"value"` ValueText string `json:"valueText"` } `json:"now"` PreviousClose struct { Value int `json:"value"` ValueText string `json:"valueText"` } `json:"previousClose"` OneWeekAgo struct { Value int `json:"value"` ValueText string `json:"valueText"` } `json:"oneWeekAgo"` OneMonthAgo struct { Value int `json:"value"` ValueText string `json:"valueText"` } `json:"oneMonthAgo"` OneYearAgo struct { Value int `json:"value"` ValueText string `json:"valueText"` } `json:"oneYearAgo"` } `json:"fgi"` } // GetFgi api実行 func (fgi *APIClientFgi) GetFgi() (StructFgi, error) { url := "https://fear-and-greed-index.p.rapidapi.com/v1/fgi" req, _ := http.NewRequest("GET", url, nil) req.Header.Add("x-rapidapi-host", fgi.host) req.Header.Add("x-rapidapi-key", fgi.key) res, err := http.DefaultClient.Do(req) if err != nil { return StructFgi{}, nil } defer res.Body.Close() body, err := ioutil.ReadAll(res.Body) if err != nil { return StructFgi{}, nil } var fgiStruct StructFgi if err := json.Unmarshal(body, &fgiStruct); err != nil { log.Fatal(err) } return fgiStruct, nil }json-to-goで生成したstructを呼び出しjson.Unmarshalでstructに格納しています。
models/fgi.go
このファイルでは上記でstructに格納したapi情報を展開してDBにINSERTしていきます。
package models import ( "fmt" "index-indicator-apis/mysql" "time" "index-indicator-apis/config" "index-indicator-apis/fgi" ) const ( tableNameFgis = "fgis" ) // Fgis 日足格納 type Fgis struct { CreatedAt time.Time `json:"created_at,omitempty"` NowValue int `json:"now_value,omitempty"` NowText string `json:"now_text,omitempty"` PcValue int `json:"pc_value,omitempty"` PcText string `json:"pc_text,omitempty"` OneWValue int `json:"one_w_value,omitempty"` OneWText string `json:"one_w_text,omitempty"` OneMValue int `json:"one_m_value,omitempty"` OneMText string `json:"one_m_text,omitempty"` OneYValue int `json:"one_y_value,omitempty"` OneYText string `json:"one_y_text,omitempty"` } //initFgis マイグレーション func initFgis() { var err error db, err := mysql.SQLConnect() if err != nil { panic(err.Error()) } defer db.Close() db.AutoMigrate(&Fgis{}) } // NewFgis fgi.StructFgiを受け取り、Fgisに変換して返す func NewFgis(f fgi.StructFgi) *Fgis { createdAt := time.Now() nowValue := f.Fgi.Current.Value nowText := f.Fgi.Current.ValueText pcValue := f.Fgi.PreviousClose.Value pcText := f.Fgi.PreviousClose.ValueText oneWValue := f.Fgi.OneWeekAgo.Value oneWText := f.Fgi.OneWeekAgo.ValueText oneMValue := f.Fgi.OneMonthAgo.Value oneMText := f.Fgi.OneMonthAgo.ValueText oneYValue := f.Fgi.OneYearAgo.Value oneYText := f.Fgi.OneYearAgo.ValueText return &Fgis{ createdAt, nowValue, nowText, pcValue, pcText, oneWValue, oneWText, oneMValue, oneMText, oneYValue, oneYText, } } // Create NewFgisをsaveする func (f *Fgis) Create() error { db, err := mysql.SQLConnect() if err != nil { panic(err.Error()) } defer db.Close() db.Create(&f) return err } // CreateNewFgis migration後にapiを叩きdbに保存する func CreateNewFgis() error { // initFgis() migration fgiClient := fgi.New(config.Config.FgiAPIKey, config.Config.FgiAPIHost) f, err := fgiClient.GetFgi() if err != nil { return err } fgi := NewFgis(f) fmt.Println(fgi) fmt.Println(fgi.Create()) return err }initFgis()ではgormのメソッドをつかってマイグレーションしています。
apiの情報を先ほどstructに格納したので、それを展開してさらに展開したvalueを格納するstructを用意するということですね。
db.AutoMigrate(&Fgis{})
こちらがgormのメソッド AutoMigrateメソッドです。
事前に用意した構造体の名前をテーブル名としてマイグレーションしてくれます。この場合だと
fgisというテーブルがmysqlに作成されます。
func NewFgis(f fgi.StructFgi) *Fgis{}
こちらではapiのデータを格納している StructFgiの中身を展開してINSERTするために用意した構造体(マイグレーションした)の中に格納してます。
func (f *Fgis) Create() error {}
こちらのメソッドではmysqlファイルで作成した関数のSQLConnect()でdbと接続後に
db.Create(&f)
とすることでINSERTを実現しています。 .Createがgormのメソッドです。 .Create(&struct)とすることでテーブル名と対応しているstructの情報をINSERTしてくれます。最後に
CreateNewFgis()
で用意した関数とメソッドを実行しています。この関数をmain.goから呼び出せば無事に実行されることができました。
- gormでは主キーとなるIDは自動で生成されるので宣言する必要はありません。
以上です!
- 投稿日:2020-11-21T01:32:22+09:00
LeetCodeに毎日挑戦してみた 13. Roman to Integer (Python、Go)
はじめに
無料英単語サイトE-tanを運営中の@ishishowです。
プログラマとしての能力を上げるために毎日leetcodeに取り組み、自分なりの解き方を挙げていきたいと思います。
Leetcodeとは
leetcode.com
ソフトウェア開発職のコーディング面接の練習といえばこれらしいです。
合計1500問以上のコーデイング問題が投稿されていて、実際の面接でも同じ問題が出されることは多いらしいとのことです。Go言語入門+アルゴリズム脳の強化のためにGolangとPythonで解いていこうと思います。(Pythonは弱弱だが経験あり)
4問目(問題13)
13. Roman to Integer
- 問題内容(日本語訳)
:ローマ数字は、7つの異なる記号で表され
I
、V
、X
、L
、C
、D
とM
。
シンボル 値
I 1
V 5
X 10
L 50
C 100
D 500
M 1000たとえば 、ローマ数字の`2`よう`II`に書かれていて、2つだけが足し合わされています。`12`は、と書かれて `XII`います`X + II`。これは単純にです。番号`27`は、と書かれて`XXVII`います`XX + V + II`。 ローマ数字は通常、左から右に最大から最小に書かれます。ただし、4の数字はではありません`IIII`。代わりに、4番目の数字は`IV`。と書かれています。1つは5の前にあるので、それを減算して4にします。同じ原則が、と書かれて`IX`いる9番にも当てはまります。減算が使用される6つの例があります: - `I``V`(5)と`X`(10)の前に置いて4と9にすることができます。 - `X``L`(50)と`C`(100)の前に置いて40と90にすることができます。 - `C``D`(500)と`M`(1000)の前に配置して、400と900を作成できます。 ローマ数字が与えられたら、それを整数に変換します。Example 1:
Input: s = "III" Output: 3Example 2:
Input: s = "IV" Output: 4Example 3:
Input: s = "IX" Output: 9Example 4:
Input: s = "LVIII" Output: 58 Explanation: L = 50, V= 5, III = 3.Example 5:
Input: s = "MCMXCIV" Output: 1994 Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.ヒント
I - 1 V - 5 X - 10 L - 50 C - 100 D - 500 M - 1000 **Rules:** \* If I comes before V or X, subtract 1 eg: IV = 4 and IX = 9 \* If X comes before L or C, subtract 10 eg: XL = 40 and XC = 90 \* If C comes before D or M, subtract 100 eg: CD = 400 and CM = 900考え方
- ヒントを参考にハッシュマップを作る
- 文字列を一文字ずつ読んでいき、文字に対応する数字とその後の文字に対応する数字を比較して大きければそのまま足して、小さければその文字を引いた値を足すようにする(コードを見たほうが早いかもしれない)
説明
Goはmap関数で初期値を設定する。(1.Two Sumの問題でmakeを使ったが、今回は初期値が入っているのでmapでよいです)
Pythonは文字列操作簡単なので後を見てますが、Goでは配列に直して、前の文字を見ています。
- 解答コード
class Solution(object): def romanToInt(self, s): roman = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000} res, i = 0, 0 for i in range(len(s)): curr, nxt = s[i], s[i+1:i+2] if nxt and roman[curr] < roman[nxt]: res -= roman[curr] else: res += roman[curr] return resスライスを使うと文字列操作が楽です
- Goでも書いてみます!
import "strings" func romanToInt(s string) int { var number int = 0 var carry int = 0 hashT := map[string]int{ "I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000, } for _, v := range strings.Split(s, "") { if carry < hashT[v] { number = number - (carry * 2) + hashT[v] } else { number = number + hashT[v] } carry = hashT[v] } return number }carryという変数で前の数字を見ています。一度、前の数字を足しているので後の数字の方が大きかった時に二回その数字を引いています。
また、文字列を配列にするためにsplitを使ったのでstringsパッケージをインポートしました。
GoとPythonの実行時間
左から、RunTime, Memory, 言語です。