Thursday, October 28, 2021

[Golang] The example function of converting Struct or Map data to Map[string]interface{} Type

    I recently encountered a use case that I need to convert my struct or map value to the type of map[string]interface{}. After surveying and studying for a while, I figure out how to deal with this kind of task and the way to do it.

    The following function ConvertStructToMap()  is the example of converting Struct or Map data to Map[string]interface{} Type. It receives the argument as interface type and uses reflect function to check the receiver type is correct and what we want. But, it has a constrain, which if you give a map, and Map's key type must be string.

// ConvertStructToMap()
func ConvertStructToMap(message interface{}) (map[string]interface{}, error) {
msg := reflect.ValueOf(message)
msgtype := msg.Type()

// support Struct
if msgtype.Kind() == reflect.Struct {
// message should be tagged by "codec" or "msg"
kv := make(map[string]interface{})
fields := msgtype.NumField()
for i := 0; i < fields; i++ {
field := msgtype.Field(i)
name := field.Name
if n1 := field.Tag.Get("json"); n1 != "" {
name = n1
} else if n2 := field.Tag.Get("msg"); n2 != "" {
name = n2
}
kv[name] = msg.FieldByIndex(field.Index).Interface()
}
return kv, nil
}
// support map[string]interface{} or map[string]string
if msgtype.Kind() != reflect.Map {
return nil, errors.New("message must be a map")
} else if msgtype.Key().Kind() != reflect.String {
return nil, errors.New("map keys must be strings")
}

// Get the interface{}'s current value
kv := make(map[string]interface{})
for _, k := range msg.MapKeys() {
kv[k.String()] = msg.MapIndex(k).Interface()
}
return kv, nil
}

func main() {
fmt.Println("Hello, playground")
structData := struct { Name string `json:"JsonName"` 
                       Score int `msg:"MsgScore"`} { 
                       "john smith", 30, }
kv, err := ConvertStructToMap( structData )
if err != nil {
    fmt.Println(err)
}
fmt.Println(kv)
}

How to use it? Here we go! You can try it on the Go Playground:
https://play.golang.org/p/TLKBIbSxIQj

or just take a look at the sample as follows:

// The way to use ConvertStructToMap()
func main() {
structData := struct { Name string `json:"JsonName"` 
                       Score int `msg:"MsgScore"`} { 
                       "john smith", 30, }
kv, err := ConvertStructToMap( structData )
if err != nil {
    fmt.Println(err)
}
fmt.Println(kv)
        mapData := make(map[string]int)
        mapData["Score1"] = 100
        mapData["Score2"] = 60
        kv, err = ConvertStructToMap( mapData )
        if err != nil {
    fmt.Println(err)
}
fmt.Println(kv)
}


Run Result==>

map[JsonName:john smith MsgScore:30]
map[Score1:100 Score2:60]



Monday, October 18, 2021

Python matplotlib 中文亂碼解決 in Linux or Windows

 大家是否有遇過當使用matplotlib時,遇到顯示不出中文或是中文為亂碼的問題。無論是在Anaconda內使用matplotlib或是直接在Python安裝環境內使用matplotlib,基本解決方式是一樣的。本文將以簡單與條列方式描述在Linux 或是 Windows 解決方法。

1. 下載字型的來源

https://www.fontpalace.com/font-download/SimHei/

2. 字型安裝

執行python command, 並以下列方式找到matplotlib放置ttf字型檔位置與設定檔

>>> import matplotlib
>>> matplotlib.matplotlib_fname()

根據下列不同環境的執行結果內放置ttf字型檔

Windows: 

放到: C:\Users\User\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\matplotlib\mpl-data\fonts\ttf 

修改設定檔  C:\Users\User\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\matplotlib\mpl-data\matplotlibrc

Linux:

 
放到: /usr/local/lib/python2.7/dist-packages/matplotlib/mpl-data/fonts/ttf
修改設定檔  /usr/local/lib/python2.7/dist-packages/matplotlib/mpl-data/matplotlibrc

Anaconda:


放到: /opt/conda/lib/python3.7/site-packages/matplotlib/mpl-data/fonts/ttf
修改設定檔  /opt/conda/lib/python3.7/site-packages/matplotlib/mpl-data/matplotlibrc

3. 設定檔matplotlibrc修改方式
font.family  : sans-serif
font.serif      : SimHei   <== 增加此項目

範例如下:


4. 重新載入字體

>>> from matplotlib.font_manager import _rebuild
>>> _rebuild() 



Wednesday, October 6, 2021

個人常用的 Git Commands

 0. 相關初始設定

git init
git config --global user.name "teyenliu"
git config --global user.email "teyen.liu@gmail.com"
git config --list

#git config --global http.sslverify false.
#git config --global log.decorate short
#git config --global color.ui true
#git config --global core.editor "vim"


git remote -v

#首次建立repository
#git remote add origin https://github.com/teyenliu/XXXX.git
#git branch -M main  // 更換master branch name to main
#git push -u origin master

#CRLF
#Linux: git config --global core.autocrlf input
#Windows: git config --global core.autocrlf true

#Editor
#git config --global core.editor vim
#Setup commit message template
#git config --global commit.template ~/git-template

#如果是 fork a repository, 則需要設定upstream repo
git remote set-url origin <my fork's git repo>
git remote add upstream <upstream's git repo>

# 查看到我們名下的遠端項目
git remote -v

#獲取upstream的最新版本
git fetch upstream

#將upstream merge到我們當前分支
git merge upstream/master

1. check out 另一個branch
git checkout <to this branch>
git checkout -b <create_new_branch> <based on this branch>

2. 建議使用這個方式避免無謂的merges
git pull --rebase <remote name> <branch name>

3. 當要switch branch,但是有file未 commit,可以使用下列方式暫存起來
git stash save 'stash1'

#查看在 stash 中的缓存
git stash list

#恢复暂存
git stash pop

4.  git checkout 時發生 Please move or remove them before you can switch branches.
git clean -d -fx

5. 拉下來最新的檔案
git pull --rebase upstream master
git pull --rebase upstream ConfigBase

6. 推code 到 remote repo.
git push origin master

7. 補充發送
git commit --amend
git push -f origin ConfigBase
git push -f origin master

8. 建立/刪除分支
#建立
git checkout -b <branch> 從目前分支再去建立(會新增)本端分支
git push -u origin <branch> PUSH並建立遠端分支
#刪除
git branch -d <branch>

### Branch from a previous commit using Git ###
# Create the branch using a commit hash:
git branch branch_name <commit-hash>

#Or by using a symbolic reference:
git branch branch_name HEAD~3

#To checkout the branch while creating it, use:
git checkout -b branch_name <commit-hash or HEAD~3>

9. 移動某個commit點
#回到 上一次的 commit
git reset --hard HEAD

#回到 上一次的前一次 commit
git reset --hard HEAD^

#裡面最近做的所有 HEAD 的改動
git reflog
git reset --hard 904e1ba #最近的commit

10. 如果想要打tag( 以某個commit為基礎 )
# 產生一個新的branch以某個commit
git checkout -b <tagname> <commit id>
git push origin <tagname>

# 要先把 branch push上去的原因是, 之後建立的tag如果跟brnach name相同 (例如: v0.4 ), 則 branch會發生如下訊息:
error: src refspec v0.4 matches more than one.
error: failed to push some refs
如果不小心先push tags, 則必須把tag移除後, 才能push branch.


# 查看目前有的tag
git tag -l

# 打tag
git tag -a <tagname> -m "My App description"

# 刪除tag
git tag -d <tagname>

# push all tags 到 remote端
git push origin --tags

11. 如果想要檢查 submodule 是否有更新可使用下列指令:
git submodule foreach --recursive git pull origin master

12. 強制推送到remote
git push -f

13. 拉submodule的程式碼
git submodule update --recursive --remote

14. 查看完整的Commit 資料
git log --pretty=oneline

15. 退回到特定 Commit
# where [revision] is the commit hash (for example: 12345678901234567890123456789012345678ab)
git checkout [revision] .

#To rollback to a specific commit:
git reset --hard commit_sha

#To rollback 10 commits back:
git reset --hard HEAD~10

Trouble Shooting

如果遇到Tag Name與Branch Name相同時, 會有其中一種無法上傳至遠端的錯誤:
src refspec XXX 匹配多個, 例如:
error: src refspec v0.3 matches more than one

解決方式:

1. 先刪除分支然後上傳Tag:
git branch -D testtag

或是

2. 先刪除tag然後上傳分支:
git tag -d testtag