2020年11月6日 星期五

[ 文章收集 ] List the files in a folder with Go

 Source From Here

Preface
In this article I explain how to get a list of files inside a folder on the filesystem, a task also called tree traversing, with Go. There are two handy stdlib functions that you can use depending on your goal. I list 3 ways: using filepath.Walk, ioutil.ReadDir or os.File.Readdir.

Using filepath.Walk
The path/filepath stdlib package provides the handy Walk function. It automatically scans subdirectories, though, so make sure this is what you actually want.

Usage is very simple:
  1. package main  
  2.   
  3. import (  
  4.     "fmt"  
  5.     "os"  
  6.     "path/filepath"  
  7. )  
  8.   
  9. func main() {  
  10.     var files []string  
  11.   
  12.     root := "/some/folder/to/scan"  
  13.     err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {  
  14.         files = append(files, path)  
  15.         return nil  
  16.     })  
  17.     if err != nil {  
  18.         panic(err)  
  19.     }  
  20.     for _, file := range files {  
  21.         fmt.Println(file)  
  22.     }  
  23. }  
filepath.Walk accepts a string pointing to the root folder, and a WalkFunc, a function type with signature:
  1. type WalkFunc func(path string, info os.FileInfo, err error) error  
This function is called for each iteration of the folder scan.

The info variable of type os.FileInfo is important because we can get many information on the current file: the name, size, mode, modification time, if it’s a folder or a file, and the underlying data source.

For example we could avoid processing folders by adding:
  1. if info.IsDir() {  
  2.     return nil  
  3. }  
You can exclude (or include) files to the slice based on their extension, by using filepath.Ext and passing the file path:
  1. if filepath.Ext(path) == ".dat" {  
  2.     return nil  
  3. }  
We could store the file name instead of the file path using:
  1. files = append(files, info.Name())  
And we could also define the WalkFunc in a separate closure. We just need to pass a pointer to files in visit:
  1. package main  
  2.   
  3. import (  
  4.     "fmt"  
  5.     "log"  
  6.     "os"  
  7.     "path/filepath"  
  8. )  
  9.   
  10. func visit(files *[]string) filepath.WalkFunc {  
  11.     return func(path string, info os.FileInfo, err error) error {  
  12.         if err != nil {  
  13.             log.Fatal(err)  
  14.         }  
  15.         *files = append(*files, path)  
  16.         return nil  
  17.     }  
  18. }  
  19.   
  20. func main() {  
  21.     var files []string  
  22.   
  23.     root := "/some/folder/to/scan"  
  24.     err := filepath.Walk(root, visit(&files))  
  25.     if err != nil {  
  26.         panic(err)  
  27.     }  
  28.     for _, file := range files {  
  29.         fmt.Println(file)  
  30.     }  
  31. }  
Using ioutil.ReadDir
filepath.Walk is handy but scans subfolders too, by default, which might not be what you want.

The Go stdlib also provides ioutil.ReadDir
  1. func ReadDir(dirname string) ([]os.FileInfo, error)  
ReadDir reads the directory named by dirname and returns a list of directory entries sorted by filename.

and here’s an example from the docs. ioutil.ReadDir takes a folder path as a string and returns a slice of os.FileInfo, which we described above.
  1. package main  
  2.   
  3. import (  
  4.     "fmt"  
  5.     "io/ioutil"  
  6.     "log"  
  7. )  
  8.   
  9. func main() {  
  10.     files, err := ioutil.ReadDir(".")  
  11.     if err != nil {  
  12.         log.Fatal(err)  
  13.     }  
  14.   
  15.     for _, file := range files {  
  16.         fmt.Println(file.Name())  
  17.     }  
  18. }  
Using os.File.Readdir
Internally, ioutil.ReadDir is implemented as:
  1. // ReadDir reads the directory named by dirname and returns  
  2. // a list of directory entries sorted by filename.  
  3. func ReadDir(dirname string) ([]os.FileInfo, error) {  
  4.     f, err := os.Open(dirname)  
  5.     if err != nil {  
  6.         return nil, err  
  7.     }  
  8.     list, err := f.Readdir(-1)  
  9.     f.Close()  
  10.     if err != nil {  
  11.         return nil, err  
  12.     }  
  13.     sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() })  
  14.     return list, nil  
  15. }  
as you can see it scans dirname and sorts the files by name. If you don’t need sorting you can as well use:
  1. package main  
  2.   
  3. import (  
  4.     "fmt"  
  5.     "log"  
  6.     "os"  
  7. )  
  8.   
  9. func main() {  
  10.     dirname := "."  
  11.   
  12.     f, err := os.Open(dirname)  
  13.     if err != nil {  
  14.         log.Fatal(err)  
  15.     }  
  16.     files, err := f.Readdir(-1)  
  17.     f.Close()  
  18.     if err != nil {  
  19.         log.Fatal(err)  
  20.     }  
  21.   
  22.     for _, file := range files {  
  23.         fmt.Println(file.Name())  
  24.     }  
  25. }  


[ 常見問題 ] Difference between two time.Time objects

Source From Here
Question
I have two time.Time objects and I want to get the difference between the two in terms of hours/minutes/seconds. Lets say:

  1. t1 = 2016-09-09 19:09:16 +0530 IST  
  2. t2 = 2016-09-09 19:09:16 +0530 IST  

In above case, since the difference is 0. It should give me 00:00:00. Consider another case:

  1. t1 = 2016-09-14 14:12:48 +0530 IST  
  2. t2 = 2016-09-14 14:18:29 +0530 IST  

In this case, difference would be 00:05:41.

How-To
You may use Time.Sub() to get the difference between the 2 time.Time values, result will be a value of time.Duration. When printed, a time.Duration formats itself "intelligently":

  1. package main  
  2.   
  3. import (  
  4.     "fmt"  
  5.     "time"  
  6. )  
  7.   
  8. func main() {  
  9.     t1 := time.Now()  
  10.     t2 := t1.Add(time.Second * 341)  
  11.   
  12.     fmt.Println(t1)  
  13.     fmt.Println(t2)  
  14.   
  15.     diff := t2.Sub(t1)  
  16.     fmt.Println(diff)  
  17. }  

Output:

2020-11-06 19:58:39.0127867 +0800 CST m=+0.002991401
2020-11-06 20:04:20.0127867 +0800 CST m=+341.002991401
5m41s

If you want the time format HH:mm:ss, you may constuct a time.Time value and use its Time.Format() method like this:

  1. diff := t2.Sub(t1)  
  2. out := time.Time{}.Add(diff)  
  3. fmt.Println(out.Format("15:04:05"))  

Ouptut:

00:05:41


Of course this will only work if the time difference is less than a day. If the difference may be bigger, then it's another story. The result must include days, months and years. Complexity increases significnatly. See this question (golang time.Since() with months and years) for details. The solution presented there solves this issue by showing a function with signature:

  1. func diff(a, b time.Time) (year, month, day, hour, min, sec int)  

You may use that even if your times are within 24 hours (in which case year, month and day will be 0).

2020年11月1日 星期日

[ Python 常見問題 ] Pandas recalculate index after a concatenation

 Source From Here

Question
I have a problem where I produce a pandas dataframe by concatenating along the row axis (stacking vertically).

Each of the constituent dataframes has an autogenerated index (ascending numbers). After concatenation, my index is screwed up: it counts up to n (where n is the shape[0] of the corresponding dataframe), and restarts at zero at the next dataframe.

I am trying to "re-calculate the index, given the current order", or "re-index" (or so I thought). Turns out that isn't exactly what DataFrame.reindex seems to be doing. Here is what I tried to do:
  1. train_df = pd.concat(train_class_df_list)  
  2. train_df = train_df.reindex(index=[i for i in range(train_df.shape[0])])  
It failed with "cannot reindex from a duplicate axis." I don't want to change the order of my data... just need to delete the old index and set up a new one, with the order of rows preserved.

HowTo
After vertical concatenation, if you get an index of [0, n) followed by [0, m), all you need to do is call reset_index:
  1. train_df.reset_index(drop=True)  
you can do this in place using inplace=True:
  1. >>> import pandas as pd  
  2. >>> cat_df = pd.concat([pd.DataFrame({'a':[1,2]}), pd.DataFrame({'a':[1,2]})])  
  3. >>> cat_df.index  
  4. Int64Index([0, 1, 0, 1], dtype='int64')  
  5. >>> cat_df.reset_index(drop=True, inplace=True)  
  6. >>> cat_df.index  
  7. RangeIndex(start=0, stop=4, step=1)  
  8. >>> cat_df  
  9.    a  
  10. 0  1  
  11. 1  2  
  12. 2  1  
  13. 3  2  


[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...