csv - 用于字符串比较的 Rust 嵌套迭代器中的所有权和生命周期

标签 csv struct rust iterator

我正在接触 Rust,似乎无法弄清楚如何比较两个 csv 文件的行。我怀疑我的困难来自于试图以完全错误的方式解决问题,所以我把自己扔给了 stackoverflow 的怜悯。

我正在编写一个简单的程序,它读取两个已知字段的csv文件,然后比较csv1中第j列的每个元素与csv2中所有j列的第j列的每个元素的编辑距离。目前,我的代码只成功地将 csv1 的第一行与 csv2 的所有行进行比较。

我的模式是:

  1. 使用 csv 和 serde crates(都很好)将 csvs 读入 struct Reader
  2. 创建一个 struct Compare,其中包含两行 Reader 类型,每个 csv 各一行。
  3. 为 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/

相关文章:

c - 错误 : assigning to 'int **' from incompatible type 'int [][]

rust - 尝试使用 Mongodb 池设置 Rocket 服务器时出现问题

memory - 如何调整结构体的大小?

ios - 导入CSV数据(SDK iPhone)

C fscanf 返回 null

pandas - UnicodeDecodeError : 'utf-8' codec can't decode byte 0xcc in position 3: invalid continuation byte

c - C代码错误: expected identifier or ‘(’ before ‘free_node_t’

rust - 如何漂亮地打印 Syn AST?

python - CSV 文件 : Change the position of column to row and reorganize dataset

MySQL:SQL 语法错误