在一个包含结构体的Vec中,使用自定义函数计算部分重复项的数量

3

假设我有以下示例:

struct Client {
    email: String,
    phone: String,
    details: String
}

fn main() {
    let mut clients: Vec<Client> = Vec::new();

    clients.push(Client {
        email: "john@gmail.com".to_string(),
        phone: "0123456789".to_string(),
        details: "custom details".to_string(),
    });

    clients.push(Client {
        email: "john@gmail.com".to_string(),
        phone: "0123456789".to_string(),
        details: "other details".to_string(),
    });

    clients.push(Client {
        email: "james@gmail.com".to_string(),
        phone: "9876543210".to_string(),
        details: "test".to_string(),
    });  
}

什么是在这个向量中通过检查emailphoneClient中计算部分重复项的最佳(Rust习惯用语)方法?例如,在上面的例子中将找到一个重复项。

1
你可以使用.map()函数将电子邮件和电话提取为一个元组。然后,问题就变成了计算完全重复的数量。 - kennytm
2个回答

5

一种选项是为每个客户创建一个带有(email, phone)的 HashSet。由于 HashSet 仅保留唯一元素,因此我们可以通过 clients 和集合中元素数量的差异来获取重复元素的数量:

use std::collections::HashMap;

struct Client {
    email: String,
    phone: String,
    details: String,
}

fn main() {
    let mut clients: Vec<Client> = Vec::new();

    clients.push(Client {
        email: "john@gmail.com".to_string(),
        phone: "0123456789".to_string(),
        details: "custom details".to_string(),
    });

    clients.push(Client {
        email: "john@gmail.com".to_string(),
        phone: "0123456789".to_string(),
        details: "other details".to_string(),
    });

    clients.push(Client {
        email: "james@gmail.com".to_string(),
        phone: "9876543210".to_string(),
        details: "test".to_string(),
    });

    // use as_str to get a `&str` from a String to avoid copying the string
    let uniques: HashMap<_, _> = clients.iter()
        .map(|c| (c.email.as_str(), c.phone.as_str()))
        .collect();

    let num_dups = clients.len() - uniques.len();

    assert_eq!(1, num_dups);
}

1

您经常需要知道哪些是重复项。在这种情况下,可以使用HashSet解决方案的直接扩展:

use std::collections::HashMap;

struct Client {
    email: String,
    phone: String,
    details: String,
}

impl Client {
    fn key<'a>(&'a self) -> (&'a str, &'a str) {
        (&self.email, &self.phone)
    }
}

fn main() {
    let clients = vec![Client {
                           email: "john@gmail.com".to_string(),
                           phone: "0123456789".to_string(),
                           details: "custom details".to_string(),
                       },
                       Client {
                           email: "john@gmail.com".to_string(),
                           phone: "0123456789".to_string(),
                           details: "other details".to_string(),
                       },
                       Client {
                           email: "james@gmail.com".to_string(),
                           phone: "9876543210".to_string(),
                           details: "test".to_string(),
                       }];

    let mut keyed = HashMap::new();
    for c in &clients {
        keyed.entry(c.key()).or_insert(vec![]).push(c)
    }

    for (k, v) in &keyed {
        if v.len() > 1 {
            println!("Key {:?} has {} duplicates!", k, v.len());
        }
    }
}

注意在Client上使用一个方法来将键控逻辑放在一个地方,使用vec![]来减少需要显式可变性的数量,而且不需要指定clients的类型,因为它可以被推断出来。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接