如果我有一个csv读入结构,我怎么能操纵输入来构建我想要的结构?我在各种教程后陷入困境。这是我最接近的。
我基本上想要打开一个csv,读取所选列,确保在引用该列时从同一行记录该值。然后以可以放入数据库的格式生成数据。
示例CSV:
Ignore,Customer,Fruit,Number
123,A,Apple,1
123,A,Apple,3
123,B,Orange,4
123,C,Melon,5
示例代码:
package main
import (
"bufio"
"encoding/csv"
"encoding/json"
"fmt"
"io"
"log"
"os"
)
type Account struct {
Customer string `json:"Customer"`
LineItem *LineItem `json:"LineItem"`
}
type LineItem struct {
ProductName string `json:"ProductName"`
Count string `json:"Count"`
}
func main() {
csvFile, _ := os.Open("/home/frank/gocode/src/local/billing/fruit.csv")
reader := csv.NewReader(bufio.NewReader(csvFile))
var billData []Account
for {
line, error := reader.Read()
if error == io.EOF {
break
} else if error != nil {
log.Fatal(error)
}
billData = append(billData, Account{
Customer: line[1],
LineItem: &LineItem{
ProductName: line[2],
Count: line[3],
},
})
}
billingJson, _ := json.Marshal(billData)
fmt.Println(string(billingJson))
}
目前的输出是:
[{"Customer":"Customer","LineItem":{"ProductName":"Fruit","Count":"Number"}},{"Customer":"A","LineItem":{"ProductName":"Apple","Count":"1"}},{"Customer":"A","LineItem":{"ProductName":"Apple","Count":"3"}},{"Customer":"B","LineItem":{"ProductName":"Orange","Count":"4"}},{"Customer":"C","LineItem":{"ProductName":"Melon","Count":"5"}}]
我想摆脱第一条记录,所以不保留标题。 e.g。
[{"Customer":"A","LineItem":{"ProductName":"Apple","Count":"1"}},{"Customer":"A","LineItem":{"ProductName":"Apple","Count":"3"}},{"Customer":"B","LineItem":{"ProductName":"Orange","Count":"4"}},{"Customer":"C","LineItem":{"ProductName":"Melon","Count":"5"}}]
合并,因此客户A是包含LineItems的一条记录,例如
[{"Customer":"A","LineItem":{"ProductName":"Apple","Count":"1"},"LineItem":{"ProductName":"Apple","Count":"3"}},{"Customer":"B","LineItem":{"ProductName":"Orange","Count":"4"}},{"Customer":"C","LineItem":{"ProductName":"Melon","Count":"5"}}]
任何最佳做法 - 欢迎使用其他方法(不确定这里的地图是否更好)。希望有足够的信息来帮助我。
答案 0 :(得分:3)
摆脱第一个条目就像#wrapper
一样简单。那,或者做一个初始读取来拉取列名。
在第二部分中,您当前的数据结构不允许一对多关系(每个Account只有一个LineItem)。之后您需要在列表上进行一些处理。 CSV文件必须是1:1,因为每一行都被视为一个独立的记录。最简单的方法是通过使用地图来实现一对多,但您也可以简单地循环切片(保留更接近现有代码):
https://play.golang.org/p/3uevo0taKR5
img {
max-width: 80px;
}
#wrapper {
display: inline-block;
padding: 1em;
background-color: rgba(0, 0, 255, .2);
}
.image_off {
display: block;
}
.image_on {
display: none;
}
#wrapper:hover .image_off {
display: none;
}
#wrapper:hover .image_on {
display: block;
}
#wrapper .text {
visibility: hidden;
}
#wrapper:hover .text {
visibility: visible;
}
输出:
<div id="wrapper">
<img class="image_off" src="//pbs.twimg.com/profile_images/723561620761391104/BQmg7aTz_400x400.jpg">
<img class="image_on" src="//www.clickborde.com.br/image/data/produtos/prod_2109_815807521.jpg">
<p class="text">TEXT TEXT TEXT TEXT</p>
</div>
最后,我建议您使用billData = billData[1:]
或类似的错误变量。 package main
import (
"bytes"
"encoding/csv"
"encoding/json"
"fmt"
"io"
"log"
)
var data = `Ignore,Customer,Fruit,Number
123,A,Apple,1
123,A,Apple,3
123,B,Orange,4
123,C,Melon,5`
type Account struct {
Customer string `json:"Customer"`
LineItems []LineItem `json:"LineItems"`
}
type LineItem struct {
ProductName string `json:"ProductName"`
Count string `json:"Count"`
}
func main() {
reader := csv.NewReader(bytes.NewBufferString(data))
// Read column label data and discard
if _, err := reader.Read(); err != nil {
log.Fatal(err)
}
var billData []Account
for {
line, err := reader.Read()
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
found := false
for i := range billData {
if billData[i].Customer == line[1] {
found = true
billData[i].LineItems = append(billData[i].LineItems, LineItem{
ProductName: line[2],
Count: line[3],
})
break
}
}
if !found {
billData = append(billData, Account{
Customer: line[1],
LineItems: []LineItem{
{
ProductName: line[2],
Count: line[3],
},
},
})
}
}
billingJson, err := json.MarshalIndent(billData, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(billingJson))
}
是内置错误类型的名称,因此通过命名您的变量,您将隐藏类型并使得无法在同一范围内声明该类型的变量。虽然这不会影响您当前的代码,但它仍然是非常糟糕的做法,最终可能会让您陷入困境。
答案 1 :(得分:0)
可以使用:
这可能是:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"github.com/jszwec/csvutil"
)
type Account struct {
Customer string `json:"Customer"`
LineItems []LineItem `json:"LineItems"`
}
type LineItem struct {
ProductName string `json:"ProductName"`
Count string `json:"Count"`
}
type CsvEntry struct {
Customer string
Fruit string
Number string
}
func main() {
// read csv
content, _ := ioutil.ReadFile("./fruits.csv")
var entries []CsvEntry
csvutil.Unmarshal(content, &entries)
// aggregate by customer name
customersMap := map[string][]LineItem{}
for _, bill := range entries {
customersMap[bill.Customer] = append(customersMap[bill.Customer], LineItem{bill.Fruit, bill.Number})
}
// build output structure
accounts := []Account{}
for customer, bill := range customersMap {
accounts = append(accounts, Account{customer, bill})
}
// print json
billingJson, _ := json.Marshal(accounts)
fmt.Println(string(billingJson))
}
此支持列排列。