代码之家  ›  专栏  ›  技术社区  ›  gfgm

rust中嵌套迭代器的所有权和生存期用于字符串比较

  •  0
  • gfgm  · 技术社区  · 6 年前

    我的脚趾生锈了,似乎不知道如何比较两个csv文件的行。我怀疑我的困难来自于试图以完全错误的方式解决问题,所以我将自己投入到了StackOverflow的仁慈中。

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

    我的模式是:

    1. 将CSV读取到 struct Reader 使用csv和serde板条箱(都很好)。
    2. 创建一个 struct Compare 它包含两行类型阅读器,每个csv一行。
    3. 编写一个返回字符串距离的比较方法。

    我有下面的核心代码片段,可以在Rust Playground中访问整个代码。 here .

    这个 struct Record 将举行一个排,

    #[derive(Debug,Deserialize)]
    struct Record {
        mp: String,
        party: String,
        constit: String,
        position: String,
        group: String,
    }
    

    以及 结构比较 把两行放在一起。我让它借用这个值是因为我不断地得到一个复制错误——但可以说,这就是我的问题开始的地方!

    #[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);
        }
    }
    

    我试图通过初始化对象来解决我的问题 comp 在第二个for循环之前,但我似乎无法让它工作。初始化需要一个默认方法,我试图为记录写入该方法。我想我让它工作了,但后来遇到了麻烦,因为我在第二个for循环中分配的对象的生命周期太短,无法维持足够长的时间来打印。这让我非常确信我可能是在错误地解决这个问题。

    提前道歉:这是一个教学项目,所以我来这里接受教育。

    1 回复  |  直到 6 年前
        1
  •  2
  •   rodrigo    6 年前

    代码的问题实际上并不是很与信任有关,而是当你从读者那里读到代码时,你在消耗他们。您的代码基本上是这样的(在伪代码中):

    file1 = open("file1");
    file2 = open("file2");
    for line1 in read_lines(file1):
        for line2 in read_lines(file2):
            compare(line1, line2)
    

    这个 file1 没关系,也没关系 file2 第一次阅读。但是在外循环的第二次迭代中 文件2 在文件的末尾,因此不再从中读取行,循环结束。

    更简单的解决方案是阅读 文件2 每一次:

    file1 = open("file1");
    for line1 in read_lines(file1):
        file2 = open("file2");
        for line2 in read_lines(file2):
            compare(line1, line2)
    

    它不是很有效,因为您一次又一次地读取同一个文件。

    如果你只想读一次,你可以收集 Records 文件2 变成一个 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());
        }
    }