20201121のGoに関する記事は3件です。

golangのos/execでMakefileのmakeコマンドを実行しようとすると2回目以降の実行がエラーになる

原因

わからん

対処方法

シェルでmakeコマンドを呼び出すようにする

Go側

  • フルパスじゃなくても大丈夫のはず
        cmd := exec.Command("/home/yuta/AWS/go/bin/exec.sh", domain.Name)
        cmd.Run()

シェル側

  • 事前にchmodで実行権限をつけてあげる
exec.sh
#!/bin/sh

cd /home/yuta/AWS
make make-env-config ENV_FILE=.env DOMAIN_NAME=${1}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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は自動で生成されるので宣言する必要はありません。

以上です!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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つの異なる記号で表され IVXLCDM
シンボル 値
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: 3

Example 2:

Input: s = "IV"
Output: 4

Example 3:

Input: s = "IX"
Output: 9

Example 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 

考え方

  1. ヒントを参考にハッシュマップを作る
  2. 文字列を一文字ずつ読んでいき、文字に対応する数字とその後の文字に対応する数字を比較して大きければそのまま足して、小さければその文字を引いた値を足すようにする(コードを見たほうが早いかもしれない)

説明

  1. Goはmap関数で初期値を設定する。(1.Two Sumの問題でmakeを使ったが、今回は初期値が入っているのでmapでよいです)

  2. 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, 言語です。

キャプチャ.PNG

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む