想法是:
给定一个大型虚拟 CSV(100 万行)包含客户数据样本,并按照以下目标进行处理:
- 从 CSV 中提取数据
- 计算有多少数据/行
- 对每个城市的客户数量进行分组
- 按客户数量从高到低对城市进行排序
- 计算处理时间
客户的 CSV 示例可以在此处下载 https://github.com/datablist/sample-csv-files
加载和提取数据
显然 Go 有用于 CSV 处理的标准库。我们不再需要第三方依赖来解决我们的问题,这很好。所以解决方案非常简单:
// open the file to a reader interface c, err := os.Open("../data/customers-1000000.csv") if err != nil { log.Fatal(err) } defer c.Close() // load file reader into csv reader // Need to set FieldsPerRecord to -1 to skip fields checking r := csv.NewReader(c) r.FieldsPerRecord = -1 r.ReuseRecord = true records, err := r.ReadAll() if err != nil { log.Fatal(err) }
- 从给定路径打开文件
- 将打开的文件加载到 csv 阅读器
- 将所有提取的 csv 记录/行值保存到记录切片中以供以后处理
FieldsPerRecord 设置为 -1,因为我想跳过对行的字段检查,因为每种格式的字段或列数可能不同
在此状态下,我们已经能够从 csv 加载和提取所有数据,并准备好进入下一个处理状态。我们还可以使用函数 len(records) 知道 CSV 中有多少行。
将总客户分组到每个城市
现在我们可以迭代记录并创建包含城市名称和总客户的地图,如下所示:
["Jakarta": 10, "Bandung": 200, ...]
csv 行中的城市数据位于第 7 个索引,代码如下所示
// create hashmap to populate city with total customers based on the csv data rows // hashmap will looks like be ["city name": 100, ...] m := map[string]int{} for i, record := range records { // skip header row if i == 0 { continue } if _, found := m[record[6]]; found { m[record[6]]++ } else { m[record[6]] = 1 } }
如果城市地图不存在,则创建新地图并将客户总数设置为1。否则只需增加给定城市的总数。
现在我们的地图 m 包含城市的集合以及其中有多少客户。至此我们已经解决了每个城市有多少客户的分组问题。
对总客户数进行排序
我试图找到标准库中是否有任何函数可以对地图进行排序,但不幸的是我找不到它。排序仅适用于切片,因为我们可以根据索引位置重新排列数据顺序。所以,是的,让我们从当前的地图中切出一个切片。
// convert to slice first for sorting purposes dc := []CityDistribution{} for k, v := range m { dc = append(dc, CityDistribution{City: k, CustomerCount: v}) }
现在我们如何按 CustomerCount 从最高到最低排序?最常见的算法是使用气泡空头。虽然它不是最快的,但它可以完成这项工作。
冒泡排序是最简单的排序算法,如果相邻元素的顺序错误,它的工作原理是重复交换相邻元素。该算法不适合大型数据集,因为其平均和最坏情况时间复杂度相当高。
参考:https://www.geeksforgeeks.org/bubble-sort-algorithm/
使用我们的切片,它将循环数据并检查索引的下一个值,如果当前数据小于下一个索引,则交换它。详细算法可以在参考网站查看。
现在我们的排序过程可能是这样的
// open the file to a reader interface c, err := os.Open("../data/customers-1000000.csv") if err != nil { log.Fatal(err) } defer c.Close() // load file reader into csv reader // Need to set FieldsPerRecord to -1 to skip fields checking r := csv.NewReader(c) r.FieldsPerRecord = -1 r.ReuseRecord = true records, err := r.ReadAll() if err != nil { log.Fatal(err) }
循环结束时,最后的切片将为我们提供排序后的数据。
计算处理时间
计算处理时间非常简单,我们获取执行程序主进程之前和之后的时间戳并计算差值。在 Go 中,方法应该足够简单:
["Jakarta": 10, "Bandung": 200, ...]
结果
使用命令运行程序
// create hashmap to populate city with total customers based on the csv data rows // hashmap will looks like be ["city name": 100, ...] m := map[string]int{} for i, record := range records { // skip header row if i == 0 { continue } if _, found := m[record[6]]; found { m[record[6]]++ } else { m[record[6]] = 1 } }
打印出来的是行数、排序数据和处理时间。像下面这样:
正如 Go 性能所预期的那样,它在 1 秒内处理了 100 万行 csv!
所有已完成的代码已发布在我的 Github 存储库上:
https://github.com/didikz/csv-processing/tree/main/golang
经验教训
- Go 中的 CSV 处理已经在标准库中可用,无需使用第 3 方库
- 处理数据非常简单。面临的挑战是找出如何对数据进行排序,因为需要手动进行
想到什么?
我认为我当前的解决方案可能可以进一步优化,因为我循环提取了 csv 的所有记录来映射,如果我们检查 ReadAll() 源,它还有循环来根据给定的文件读取器创建切片。这样,1 百万行可以为 1 百万数据生成 2 个循环,这不太好。
我想如果我可以直接从文件读取器读取数据,它只需要 1 个循环,因为我可以直接从中创建地图。除了记录切片将在其他地方使用,但在本例中不使用。
我还没有时间弄清楚,但我也认为如果我手动完成会有一些缺点:
- 可能需要处理更多解析过程中的错误
- 我不确定它会减少多少处理时间来考虑解决方法是否值得
编码快乐!
以上是使用 Go 处理大型 CSV的详细内容。更多信息请关注PHP中文网其他相关文章!

Go的"strings"包提供了丰富的功能,使字符串操作高效且简单。1)使用strings.Contains()检查子串。2)strings.Split()可用于解析数据,但需谨慎使用以避免性能问题。3)strings.Join()适用于格式化字符串,但对小数据集,循环使用 =更有效。4)对于大字符串,使用strings.Builder构建字符串更高效。

Go语言使用"strings"包进行字符串操作。1)拼接字符串使用strings.Join函数。2)查找子串使用strings.Contains函数。3)替换字符串使用strings.Replace函数,这些函数高效且易用,适用于各种字符串处理任务。

资助bytespackageingoisesential foreffited byteSemanipulation,uperingFunctionsLikeContains,index,andReplaceForsearchingangingAndModifyingBinaryData.itenHancesperformanceNandCoderAceAnibility,MakeitiTavitalToolToolToolToolToolToolToolToolToolForhandLingBinaryData,networkProtocols,networkProtocoLss,networkProtocols,andetFilei

Go语言使用"encoding/binary"包进行二进制编码与解码。1)该包提供binary.Write和binary.Read函数,用于数据的写入和读取。2)需要注意选择正确的字节序(如BigEndian或LittleEndian)。3)数据对齐和错误处理也是关键,确保数据的正确性和性能。

1)usebybytes.joinforconcatenatinges,2)bytes.bufferforincrementalWriter,3)bytes.indexorbytes.indexorbytes.indexbyteforsearching bytes.bytes.readereforrednerncretinging.isnchunk.ss.ind.inc.softes.4)

theencoding/binarypackageingoiseforporptimizingBinaryBinaryOperationsDuetoitssupportforendiannessessandefficityDatahandling.toenhancePerformance:1)usebinary.nativeendiandiandiandiandiandiandiandian nessideendian toavoid avoidByteByteswapping.2)

Go的bytes包主要用于高效处理字节切片。1)使用bytes.Buffer可以高效进行字符串拼接,避免不必要的内存分配。2)bytes.Equal函数用于快速比较字节切片。3)bytes.Index、bytes.Split和bytes.ReplaceAll函数可用于搜索和操作字节切片,但需注意性能问题。

字节包提供了多种功能来高效处理字节切片。1)使用bytes.Contains检查字节序列。2)用bytes.Split分割字节切片。3)通过bytes.Replace替换字节序列。4)用bytes.Join连接多个字节切片。5)利用bytes.Buffer构建数据。6)结合bytes.Map进行错误处理和数据验证。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器

SublimeText3 英文版
推荐:为Win版本,支持代码提示!

SublimeText3 Linux新版
SublimeText3 Linux最新版

Dreamweaver CS6
视觉化网页开发工具