Home > Enterprise >  How to reorder a CSV file to group by contents of a particular column
How to reorder a CSV file to group by contents of a particular column

Time:08-01

I am very new go Golang and my question is not cleared also, but this is what I am trying to achieve. I have a csv file as follow, as I am mainly trying to re-arrange/sort last column(status=passed,failed/skipped)

test,test-cat,skipped
test,test-cat,failed
test,test-cat,passed
test,test-cat,skipped
test,test-cat,passed
test,test-cat,failed

Expecting last column to be grouped them together if it has same status.

test,test-cat,skipped
test,test-cat,skipped
test,test-cat,failed
test,test-cat,failed
test,test-cat,passed
test,test-cat,passed

With this codes I did, it does not look good:-) but it works as I wanted.

package main
import (
        "bufio"
        "fmt"
        "os"
        "strings"
)
func main() {
        var FailStat, SkipStat,PassStat []string
      
        file, err := os.Open("test.csv")

        if err != nil {
                fmt.Println(err)
        } else {
                scanner := bufio.NewScanner(file)
                for scanner.Scan() {
                        line := scanner.Text()
                        if strings.Contains(line, "failed") {
                                FailStat = append(FailStat, line)

                        }
                        if strings.Contains(line, "skipped") {
                                SkipStat = append(SkipStat, line)

                        }
                        if strings.Contains(line, "passed") {
                                PassStat = append(PassStat, line)

                        }                       
                }
        }
        file.Close()

        var finalstat []string
        finalstat = append(SkipStat, FailStat...)
        finalstat = append(finalstat, PassStat...)

        for _, line := range finalstat {
           fmt.Println(line)
   }
}

Test-Run:

$ ./readfile 
test,test-cat,skipped
test,test-cat,skipped
test,test-cat,failed
test,test-cat,failed
test,test-cat,passed
test,test-cat,passed

There must be a many better ways, please advice. Sorry for newbie question!

CodePudding user response:

Inian's solution will work if the order of the status groupings doesn't matter (because of map's design, you should never expect to get the same ordering of the groups from run to run).

If you need the groups consistently ordered, that is actually sorted:

package main

import (
    "encoding/csv"
    "io"
    "log"
    "os"
    "sort"
    "strings"
)

type Row struct {
    Name, Category, Status string
}

func main() {
    in := `test,test-cat,skipped
test,test-cat,failed
test,test-cat,passed
test,test-cat,skipped
test,test-cat,passed
test,test-cat,failed
`
    r := csv.NewReader(strings.NewReader(in))

    rows := make([]Row, 0)
    for {
        record, err := r.Read()
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Fatal(err)
        }
        row := Row{record[0], record[1], record[2]}
        rows = append(rows, row)
    }

    sort.Slice(rows, func(i, j int) bool { return rows[i].Status < rows[j].Status })

    w := csv.NewWriter(os.Stdout)

    for _, row := range rows {
        w.Write([]string{row.Name, row.Category, row.Status})
    }
    w.Flush()

    if err := w.Error(); err != nil {
        log.Fatal(err)
    }
}

and we get:

test,test-cat,failed
test,test-cat,failed
test,test-cat,passed
test,test-cat,passed
test,test-cat,skipped
test,test-cat,skipped

Change the < to > in the anonymous func for sort.Slice to reverse the order of the sort.

Go Playground

If you don't want to mess with the Row struct and convert between []Row and [][]string:

// ...
rows := make([][]string, 0)
for {
    row, err := r.Read()
    // ...
    rows = append(rows, row)
}

sort.Slice(rows, func(i, j int) bool { return rows[i][2] < rows[j][2] })

w := csv.NewWriter(os.Stdout)

for _, row := range rows {
    w.Write(row)
}
// ...

Go Playground

In a comment you mentioned wanting a specific order of the groups, and now I can in your original code what you were aiming for

  • Related