我正在接触 Rust,似乎无法弄清楚如何比较两个 csv 文件的行。我怀疑我的困难来自于试图以完全错误的方式解决问题,所以我把自己扔给了 stackoverflow 的怜悯。
我正在编写一个简单的程序,它读取两个已知字段的csv文件,然后比较csv1中第j列的每个元素与csv2中所有j列的第j列的每个元素的编辑距离。目前,我的代码只成功地将 csv1 的第一行与 csv2 的所有行进行比较。
我的模式是:
- 使用 csv 和 serde crates(都很好)将 csvs 读入
struct Reader
。 - 创建一个
struct Compare
,其中包含两行 Reader 类型,每个 csv 各一行。 - 为 Compare 编写一个返回字符串距离的方法。
我有下面的核心代码片段,整个代码可以在 rust playground 中访问 here .
struct Record
将保存一行,
#[derive(Debug,Deserialize)]
struct Record {
mp: String,
party: String,
constit: String,
position: String,
group: String,
}
struct Compare
将两行放在一起。我让它借用了值,因为我一直收到复制错误——但可以说这就是我的问题开始的地方!
#[derive(Debug)]
struct Compare<'a> {
dfa: &'a Record,
dfb: &'a Record,
}
我在这里实现了一个比较方法,它计算两行中每个元素的 Jaro-Winkler 距离,并返回在别处定义的另一个结构类型(完整文件请参见上面的 rust playground 链接):
impl <'a> Compare<'a> {
fn jwdist(&self) -> Stringcomps {
let res = Stringcomps {
mp: strsim::jaro_winkler(&self.dfa.mp, &self.dfb.mp),
party: strsim::jaro_winkler(&self.dfa.party, &self.dfb.party),
constit: strsim::jaro_winkler(&self.dfa.constit, &self.dfb.constit),
position: strsim::jaro_winkler(&self.dfa.position, &self.dfb.position),
group: strsim::jaro_winkler(&self.dfa.group, &self.dfb.group),
};
res
}
}
以下代码运行该函数(带有一些玩具数据)。它产生不正确的输出,因为它只将第一个 csv 文件的第一行与另一个 csv 文件的所有行进行比较:
fn run() -> Result<(), Box<Error>> {
// get first df
let data1 = "mp,party,constit,position,group\n
george,con,bath,whip,no\n
bob,lab,oxford,backbench,yes";
let data2 = "mp,party,constit,position,group\n
goerge,can,both,wihp,no\n
bob,lob,ofxord,backbenth,yes";
let mut rdr = csv::Reader::from_reader(data1.as_bytes());
// get second df
let mut rdr2 = csv::Reader::from_reader(data2.as_bytes());
// iterate through both and compare
for result in rdr.deserialize() {
let record: Record = result?;
for result2 in rdr2.deserialize() {
let record2: Record = result2?;
let comp = Compare{
dfa: &record,
dfb: &record2,
};
println!("{:?} compared to {:?}: {:?}", comp.dfa.mp,
comp.dfb.mp, comp.jwdist());
}
}
Ok(())
}
fn main() {
if let Err(err) = run() {
println!("error running example: {}", err);
process::exit(1);
}
}
我试图通过在第二个 for 循环之前初始化对象 comp
来解决我的问题,但我似乎无法让它工作。初始化需要一个默认方法,我试着为 Record 写了这个方法。我想我让它工作了,但后来遇到了麻烦,因为我在第二个 for 循环中分配的对象的生命周期太短,无法存活足够长的时间来打印。这让我非常确信我可能处理问题的方式有误。
提前致歉:这是一个教学项目,所以我是来接受教育的。
最佳答案
代码的问题实际上与 Rust 关系不大,而是当您从阅读器读取时正在消耗阅读器。您的代码基本上可以做到(伪代码):
file1 = open("file1");
file2 = open("file2");
for line1 in read_lines(file1):
for line2 in read_lines(file2):
compare(line1, line2)
file1
没问题,file2
第一次读取也没有问题。但是在外层循环的第二次迭代中,file2
位于文件末尾,因此不再从中读取任何行,循环结束。
更简单的解决方案是每次读取file2
:
file1 = open("file1");
for line1 in read_lines(file1):
file2 = open("file2");
for line2 in read_lines(file2):
compare(line1, line2)
效率不是很高,因为您要一遍又一遍地读取同一个文件。
如果只想读取一次,可以将file2
中的所有Records
收集到一个Vec
中,然后迭代Vec
根据需要多次:
let mut rdr = csv::Reader::from_reader(data1.as_bytes());
let mut rdr2 = csv::Reader::from_reader(data2.as_bytes());
let lines2 = rdr2.deserialize().collect::<Result<Vec<Record>, _>>()?;
for result in rdr.deserialize() {
let record: Record = result?;
for record2 in &lines2 {
let comp = Compare{
dfa: &record,
dfb: record2,
};
println!("{:?} compared to {:?}: {:?}", comp.dfa.mp,
comp.dfb.mp, comp.jwdist());
}
}
关于csv - 用于字符串比较的 Rust 嵌套迭代器中的所有权和生命周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54259336/