我将脚趾浸入Rust中,似乎无法弄清楚如何比较两个csv文件的行。我怀疑我的困难源于试图以完全错误的方式解决该问题,因此我将自己投身于stackoverflow的摆布。
我正在编写一个简单的程序,该程序读取两个已知字段的csv文件,然后比较J中所有j列的csv1中j列的每个元素与csv2中j列的每个元素的编辑距离。 ,我的代码只能成功将csv1的第一行与csv2的所有行进行比较。
我的模式是:
struct Reader
(都不错)。 struct Compare
,其中包含两行类型为Reader的行,每行csv中的一行。我下面有一些核心代码段,整个内容都可以在锈蚀的游乐场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,
}
这里,我实现了一个Compare方法,该方法计算了两行中每个元素的Jaro-Winkler距离,并返回了在其他地方定义的另一个结构类型(有关完整文件,请参见上面的rust操场的链接):
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循环内分配的对象的生命周期太短,无法生存到足以打印的时间。这让我非常确信我可能错误地解决了这个问题。
提前道歉:这是一个教学项目,所以我在这里接受教育。
答案 0 :(得分:2)
按原样,代码的问题实际上与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)
效率不是很高,因为您要一遍又一遍地读取同一文件。
如果您只想阅读一次,则可以将Records
中的所有file2
收集到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());
}
}