如何从CSV数据创建仅含i32类型评分的二维向量
解决方案
方法一:使用标准库实现
如果不想引入第三方依赖,用标准库就能完成需求。核心思路是逐行处理,跳过每行第一个字段,将剩余字段清洗后转为i32:
use std::fs; fn main() -> Result<(), Box<dyn std::error::Error>> { let content = fs::read_to_string("ratings.csv")?; let ratings: Vec<Vec<i32>> = content .lines() .filter(|line| !line.trim().is_empty()) // 跳过空行 .map(|line| { line.split(',') .skip(1) // 跳过客户名称字段 .map(|s| s.trim().parse::<i32>()) .collect::<Result<Vec<i32>, _>>() }) .collect::<Result<_, _>>()?; println!("{:?}", ratings); Ok(()) }
这段代码做了这些事:
- 读取文件内容到字符串
- 按行分割内容,过滤掉空行
- 对每行用
split(',')拆分字段,跳过第一个元素 - 对每个剩余字段先去除前后空格(匹配你示例里的格式,比如
, 0这种带空格的字段),再解析为i32 - 用嵌套的
collect::<Result<...>>()自动处理解析错误,若某行存在无法转为i32的字段,会直接返回错误
方法二:使用csv crate(更高效,推荐)
如果处理的文件较大,或者需要更健壮的CSV处理能力(比如处理带引号的字段、转义字符等),推荐用官方维护的csv crate——它采用流式处理,内存占用更低,且能兼容各种CSV规范场景。
首先在Cargo.toml里添加依赖:
[dependencies] csv = "1.2"
然后实现代码:
use csv::ReaderBuilder; fn main() -> Result<(), Box<dyn std::error::Error>> { let mut rdr = ReaderBuilder::new() .trim(csv::Trim::All) // 自动去除字段前后的空格 .from_path("ratings.csv")?; let mut ratings = Vec::new(); for result in rdr.records() { let record = result?; // 跳过第一个字段,将剩余字段转为i32 let row_ratings: Vec<i32> = record .iter() .skip(1) .map(|s| s.parse()) .collect::<Result<_, _>>()?; ratings.push(row_ratings); } println!("{:?}", ratings); Ok(()) }
为什么推荐这个方法?
- 流式读取,无需一次性加载整个文件到内存,大文件场景下性能更优
- 自动处理CSV的各种细节(比如字段中的转义逗号、引号包裹的字段)
- 通过
Trim::All配置自动去除字段前后空格,省去手动调用trim()的步骤
关于“高效”的说明
你提到逐个parse可能不够高效,但Rust的parse本身已经做了性能优化,两种方法的效率差异主要体现在文件读取和字段拆分环节:
- 标准库方法适合小文件,需要一次性加载整个文件到内存
csvcrate的流式处理更适合大文件,内部的字段拆分逻辑经过优化,比手动split更健壮高效
内容的提问来源于stack exchange,提问作者Snails
相关产品推荐
相关产品推荐

