【问题标题】:Summarizing contents of csv总结csv的内容
【发布时间】:2019-01-23 09:27:04
【问题描述】:

上下文 我正在开发一个小程序,它可以总结一团乱七八糟的账单的内容,它是 csv 格式的。

该法案有我感兴趣的三列:

  1. 事件类型。在这里,我只对此列显示为 CHARGE 的行感兴趣
  2. 成本。不言自明。
  3. 资源名称,包含服务器和集群名称。格式为 servername.clustername。

我们的想法是选择标记为费用的行,首先按集群然后按服务器名称将它们拆分,然后汇总每个的总成本。

我不禁觉得这应该很容易,但我一直在摸索这个问题,但似乎无法弄清楚。在这一点上,我应该声明我对编程相当陌生,对 GO 完全陌生。

这是我目前所拥有的:

package main

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



func main() {
    rows := readBill("bill-2018-April.csv")
    rows = calculateSummary(rows)
    writeSummary("bill-2018-April-output", rows)

}

func readBill(name string) [][]string {

    f, err := os.Open(name)

    if err != nil {
        log.Fatalf("Cannot open '%s': %s\n", name, err.Error())
    }

    defer f.Close()

    r := csv.NewReader(f)

    rows, err := r.ReadAll()

    if err != nil {
        log.Fatalln("Cannot read CSV data:", err.Error())
    }

    return rows
}

type charges struct {
    impactType string
    cost       float64
    resName    string
}
func createCharges(rows [][]string){
    charges:= []charges{}
    for i,r:=range rows {
        var c charges
        c.impactType :=r [i][10]
        c.cost := r [i][15]
        c.resName := r [i][20]
        charges = append()
    }
    return charges
} 

所以,据我所知,我现在应该隔离我感兴趣的列(即第 10、15 和 20 列)。到目前为止我所知道的是否正确?

我将如何挑选出读取“CHARGE”的行并按集群和服务器对所有内容进行切片?

总结起来应该不会太棘手,但无论出于何种原因,这真的让我很难过。

【问题讨论】:

  • 我们可以在 CSV 中提供示例数据吗?
  • 使用 `fmt.Println(string(rows)) 将 rows 转换为字符串。
  • 根据问题文本,听起来您有尚未尝试运行的代码。如果您想知道您的代码是否符合您的预期,请运行它并查看。

标签: csv go struct slice summarize


【解决方案1】:

只需使用两张地图来存储每个服务器和每个集群的总和。而且由于您对整个 CSV 不感兴趣,而只对某些行感兴趣,因此阅读所有内容有点浪费。跳过你不关心的行:

package main

import (
    "encoding/csv"
    "fmt"
    "io"
    "log"
    "strconv"
    "strings"
)

func main() {
    b := `
,,,,,,,,,,CHARGE,,,,,100.00,,,,,s1.c1
,,,,,,,,,,IGNORE,,,,,,,,,,
,,,,,,,,,,CHARGE,,,,,200.00,,,,,s2.c1
,,,,,,,,,,CHARGE,,,,,300.00,,,,,s3.c2
`

    r := csv.NewReader(strings.NewReader(b))

    byServer := make(map[string]float64)
    byCluster := make(map[string]float64)

    for i := 0; ; i++ {
        row, err := r.Read()
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Fatal(err)
        }

        if row[10] != "CHARGE" {
            continue
        }

        cost, err := strconv.ParseFloat(row[15], 64)
        if err != nil {
            log.Fatalf("row %d: malformed cost: %v", i, err)
        }

        xs := strings.SplitN(row[20], ".", 2)
        if len(xs) != 2 {
            log.Fatalf("row %d: malformed resource name", i)
        }

        server, cluster := xs[0], xs[1]

        byServer[server] += cost
        byCluster[cluster] += cost
    }

    fmt.Printf("byServer: %+v\n", byServer)
    fmt.Printf("byCluster: %+v\n", byCluster)
}

// Output:
// byServer: map[s2:200 s3:300 s1:100]
// byCluster: map[c1:300 c2:300]

在操场上试试看:https://play.golang.org/p/1e9mJf4LyYE

【讨论】:

  • 感谢您的回复!我今天就试试这种方法。
猜你喜欢
  • 2013-04-21
  • 1970-01-01
  • 2017-07-10
  • 1970-01-01
  • 2020-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多