I have two FnvHashMap which is declared like first: FnvHashMap<(i32, i32), Employee>
second: FnvHashMap<(i32, i32), Employee>
Where Employee is
pub struct Employee {
pub emp_id: i32,
pub lang_id: i32,
pub dept_id: f64,
pub description: String,
}
I need to iterate through 'first' FnvHashMap and see if there is a matching record(emp_id and lang_id) in 'second' FnvHashMap
I may not need to consider dept_id and description
Thanks in Advance.
New code after implementing nested loop
for (_, employee1) in &first {
for (_, employee2) in &second {
if employee1.emp_id == employee2.emp_id && employee1.lang_id == employee2.lang_id {
values.push(OldNew {
old: employee2,
new: employee1,
});
}
}
}
let new = first
.into_iter()
.filter(|(a, _)| !old.contains_key(a))
.map(|(_, a)| a)
.collect();
let deleted = second
.iter()
.filter(|(a, _)| !new.contains_key(a))
.map(|(&a, _)| a)
.collect();
Changes {
deleted,
new,
values,
}
pub struct Changes<T, I> {
pub deleted: Vec<I>,
pub new: Vec<T>,
pub values: Vec<OldNew<T>>,
}
expected struct `organization::models::employee_stat::Employee`, found `&organization::models::employee_stat::Employee`
Simply make two nested for loops to iterate through both maps and then compare the values you need from the two iterations of the loops, for example
for (_, employee1) in &first {
for (_, employee2) in &second {
if employee1.emp_id == employee2.emp_id && employee1.lang_id == employee2.lang_id {
/* Code here to run if a matching value is found */
}
}
}
Related
I have a struct where I've derived a couple of things.
#[derive(PartialEq, Debug)]
struct Subscriber {
id: u16,
up_speed: u32,
down_speed: u32
}
However, when I try to use PartialEq, I get told it is not implemented.
for (id, subscriber) in &new_hashmap {
let original_subscriber = original_hashmap.get(id).unwrap();
if original_subscriber == None {
changed_hashmap.insert(subscriber.id, subscriber);
} else if subscriber != original_subscriber {
changed_hashmap.insert(subscriber.id, subscriber);
}
}
Here's the compiler error.
error[E0277]: can't compare `&Subscriber` with `Option<_>`
--> src/main.rs:34:32
|
34 | if original_subscriber == None {
| ^^ no implementation for `&Subscriber == Option<_>`
|
= help: the trait `PartialEq<Option<_>>` is not implemented for `&Subscriber`
= help: the trait `PartialEq` is implemented for `Subscriber`
If I rewrite it to not put original_subscriber into its own variable, then it works.
for (id, subscriber) in &new_hashmap {
if original_hashmap.get(id) == None {
changed_hashmap.insert(subscriber.id, subscriber);
} else if subscriber != original_hashmap.get(id).unwrap() {
changed_hashmap.insert(subscriber.id, subscriber);
}
}
The rest of the code is essentially doing the following.
Create HashMap of 2 Subscriber instances.
Create another HashMap of 3 Subscriber instances, 1 of which is new, 1 of which is the same, and 1 of which has the same key but an updated value.
That is original_hashmap HashMap and new_hashmap.
The goal is to get a third HashMap of items in new_hashmap that are new to original_hashmap or have changed values.
your code does not work for 2 reasons.
If you derive PartialEq it will only work for Subscriber == Subscriber checks. You need to implement PartialEq<Type>
You are using a reference when comparing. This means you need to implement PartialEq for &Subscriber and not subscriber
This should do the trick
#[derive(PartialEq, Debug)]
struct Subscriber {
id: u16,
up_speed: u32,
down_speed: u32,
}
let subscriber = Subscriber {
id: 1,
up_speed: 100,
down_speed: 100,
};
impl PartialEq<Option<Subscriber>> for &Subscriber {
fn eq(&self, other: &Option<Subscriber>) -> bool {
match other {
Some(other) => return other == *self,
None => return false,
}
}
}
if &subscriber == None {
println!("None");
} else {
println!("Some");
}
But I am not sure if this is really what you want. I will try to implement the same and edit my answer afterwards
I suppose that's what you want to implement
use std::collections::HashMap;
#[derive(Debug, PartialEq)]
struct Subscriber {
id: u16,
up_speed: u32,
down_speed: u32,
}
impl Subscriber {
fn new(id: u16, up_speed: u32, down_speed: u32) -> Subscriber {
Subscriber {
id,
up_speed,
down_speed,
}
}
}
fn main() {
let mut old_map = HashMap::new();
old_map.insert(1, Subscriber::new(1, 1, 1));
old_map.insert(2, Subscriber::new(2, 2, 2));
let mut new_map = HashMap::new();
new_map.insert(0, Subscriber::new(0, 0, 0)); //new
new_map.insert(1, Subscriber::new(1, 1, 1)); //Same
new_map.insert(2, Subscriber::new(3, 3, 3)); //Same key but different value
let mut changed_map = HashMap::new();
//
for (key, subscriber) in &new_map {
if old_map.contains_key(&key) {
if old_map[&key] != *subscriber {
changed_map.insert(key, subscriber);
}
} else {
changed_map.insert(key, subscriber);
}
}
println!("{:?}", changed_map);
}
It will return
{2: Subscriber { id: 3, up_speed: 3, down_speed: 3 }, 0: Subscriber { id: 0, up_speed: 0, down_speed: 0 }}
I used the deref operator to avoid impl PartialEq<Subscriber> for &Subscriber but you could have done that as well
I need to draw two vectors of objects from back to front based on their distance, but these object are different structs that both have a field for its distance to the camera. How would I sort them to iterate from bigger to smaller distance?
Repro:
struct ItemA{
distance: f32,
}
struct ItemB{
distance: f32,
}
impl ItemA{
fn draw_a(&self) -> {
println!("d: {}", self.distance);
}
}
impl ItemB{
fn draw_b(&self) -> {
println!("d: {}", self.distance);
}
}
fn main() {
let vec_a = vec![ItemA{distance: 1}, ItemA{distance:4}, ItemA{distance:10}];
let vec_b = vec![ItemB{distance: 2}, ItemB{distance:6}, ItemB{distance:7}];
// Should print in order d: 10(a), d: 7(b), d: 6(b), d: 4(a), d: 2(b), d: 1(a)
}
}
Rust playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=a1b58729f60fac8312a2fadc6663c633
Here is a solution that makes use of an enum to create a type which can store both ItemA or ItemB. This is an alternative to boxing that does not rely on dynamic dispatch.
struct ItemA {
distance: f32,
}
struct ItemB {
distance: f32,
}
impl ItemA {
fn draw_a(&self) {
println!("d: {}(a)", self.distance);
}
}
impl ItemB {
fn draw_b(&self) {
println!("d: {}(b)", self.distance);
}
}
enum AB {
A(ItemA),
B(ItemB),
}
impl AB {
fn dist(&self) -> f32 {
match self {
AB::A(a) => a.distance,
AB::B(b) => b.distance,
}
}
fn draw(&self) {
match self {
AB::A(a) => a.draw_a(),
AB::B(b) => b.draw_b(),
}
}
}
fn main() {
let vec_a = vec![
ItemA { distance: 1.0 },
ItemA { distance: 4.0 },
ItemA { distance: 10.0 },
];
let vec_b = vec![
ItemB { distance: 2.0 },
ItemB { distance: 6.0 },
ItemB { distance: 7.0 },
];
let mut all = vec_a.into_iter().map(|e| AB::A(e)).collect::<Vec<_>>();
all.extend(vec_b.into_iter().map(|e| AB::B(e)));
all.sort_by(|a, b| {
b.dist()
.partial_cmp(&a.dist())
.unwrap_or(std::cmp::Ordering::Equal)
});
// Should print in order d: 10(a), d: 7(b), d: 6(b), d: 4(a), d: 2(b), d: 1(a)
for ab in all {
ab.draw();
}
}
This prints:
d: 10(a)
d: 7(b)
d: 6(b)
d: 4(a)
d: 2(b)
d: 1(a)
playground link
A solution would be to sort both Vec, then explicitly having two indices starting at 0, and printing from either vector at each step, and advancing one index, like in the merge function from mergesort. It would work, but it would be verbose.
A an other solution would be to make a Trait with two methods: a distance(&self) -> f32, which would (in your case) just return self.distance, and a kind(&self) -> &str which would return either "a" or "b", and implement this trait for both ItemA and ItemB. In the end, you can create an homogeneous vector of Box<dyn ThatTrait> and sort that. I mention this solution because I can picture it being a viable solution for a renderer which can have several kind of objects on a scene, pretty much like how graphic toolkits do too in Rust. I think that, in the end, you'll want this solution if you have a medium to big project.
However, the simplest working solution for your example is probably just to extract the wanted information from each vector, and sort that:
fn main() {
let vec_a = vec![ItemA {distance: 1.}, ItemA {distance: 4.}, ItemA {distance: 10.}];
let vec_b = vec![ItemB {distance: 2.}, ItemB {distance: 6.}, ItemB {distance: 7.}];
let mut vec_all = vec_a
.iter()
.map(|ItemA {distance}| distance)
.chain(vec_b
.iter()
.map(|ItemB {distance}| distance)
)
.collect::<Vec<_>>();
vec_all.sort_by(|a, b| a.partial_cmp(b).unwrap());
for d in vec_all {
println!("d: {}", d);
}
}
See the playground.
I am using the HashMap to store some of the value. Now I want to check whether HashMap contains keys, if not insert data else return HashMap is not empty. Below code explain that I am checking for product id, but I want to check for 2 keys product key and product url.
use std::collections::hash_map::Entry::Vacant;
pub struct Products<DB>
where
DB: DatabaseProvider,
{
database: DB,
products: HashMap<String, Product>,
}
pub struct Product {
pub product_id: String,
pub created: String,
pub product_description: String,
pub product_url: String,
}
pub async fn get_product_store_hashmap(&mut self) -> Result<()>
{
// calling the api here, once response is received, store in hashmap
let product = Product {
product_id: somedata,
created: somedata,
product_description: somedata,
product_url:somedata,
};
self.products.insert(product_id.clone(), product);
}
pub async fn insertProduct(&mut self, product:Product) -> Result<()> {
// How to check two keys are contains value.
if let Vacant(entry:Vacant::entry<(string,Product)) = self.product.entry(product_id) {
// insert the data
} else {
// retun no product id found
}
}
You can use map.contains_key to test.
Example:
fn insertProduct(map: &mut HashMap<String, Product>, product: Product) -> Result<()> {
if map.contains_key(product.product_id) || map.contains_key(product.product_url) {
Err()
} else {
map.insert(product.product_id, Product);
Ok(())
}
}
You can use Vacant and Occupied to check if key already exists or not and return result according using match
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Vacant, Occupied};
use std::io::ErrorKind;
fn main() {
let mut h: HashMap<&str, u8> = HashMap::new();
let value: &str = "a";
// h.entry(value).or_insert(1); // <- uncomment to get err result
let result = match h.entry(value) {
Vacant(entry) => {
entry.insert(1);
Ok(())
},
Occupied(_) => Err(ErrorKind::AlreadyExists)
};
println!("{:?}", result);
}
Playground
I'm trying to create some sets of Strings and then merge some of these sets so that they have the same tag (of type usize). Once I initialize the map, I start adding strings:
self.clusters.make_set("a");
self.clusters.make_set("b");
When I call self.clusters.find("a") and self.clusters.find("b"), different values are returned, which is fine because I haven't merged the sets yet. Then I call the following method to merge two sets
let _ = self.clusters.union("a", "b");
If I call self.clusters.find("a") and self.clusters.find("b") now, I get the same value. However, when I call the finalize() method and try to iterate through the map, the original tags are returned, as if I never merged the sets.
self.clusters.finalize();
for (address, tag) in &self.clusters.map {
self.clusterizer_writer.write_all(format!("{};{}\n", address,
self.clusters.parent[*tag]).as_bytes()).unwrap();
}
// to output all keys with the same tag as a list.
let a: Vec<(usize, Vec<String>)> = {
let mut x = HashMap::new();
for (k, v) in self.clusters.map.clone() {
x.entry(v).or_insert_with(Vec::new).push(k)
}
x.into_iter().collect()
};
I can't figure out why this is the case, but I'm relatively new to Rust; maybe its an issue with pointers?
Instead of "a" and "b", I'm actually using something like utils::arr_to_hex(&input.outpoint.txid) of type String.
This is the Rust implementation of the Union-Find algorithm that I am using:
/// Tarjan's Union-Find data structure.
#[derive(RustcDecodable, RustcEncodable)]
pub struct DisjointSet<T: Clone + Hash + Eq> {
set_size: usize,
parent: Vec<usize>,
rank: Vec<usize>,
map: HashMap<T, usize>, // Each T entry is mapped onto a usize tag.
}
impl<T> DisjointSet<T>
where
T: Clone + Hash + Eq,
{
pub fn new() -> Self {
const CAPACITY: usize = 1000000;
DisjointSet {
set_size: 0,
parent: Vec::with_capacity(CAPACITY),
rank: Vec::with_capacity(CAPACITY),
map: HashMap::with_capacity(CAPACITY),
}
}
pub fn make_set(&mut self, x: T) {
if self.map.contains_key(&x) {
return;
}
let len = &mut self.set_size;
self.map.insert(x, *len);
self.parent.push(*len);
self.rank.push(0);
*len += 1;
}
/// Returns Some(num), num is the tag of subset in which x is.
/// If x is not in the data structure, it returns None.
pub fn find(&mut self, x: T) -> Option<usize> {
let pos: usize;
match self.map.get(&x) {
Some(p) => {
pos = *p;
}
None => return None,
}
let ret = DisjointSet::<T>::find_internal(&mut self.parent, pos);
Some(ret)
}
/// Implements path compression.
fn find_internal(p: &mut Vec<usize>, n: usize) -> usize {
if p[n] != n {
let parent = p[n];
p[n] = DisjointSet::<T>::find_internal(p, parent);
p[n]
} else {
n
}
}
/// Union the subsets to which x and y belong.
/// If it returns Ok<u32>, it is the tag for unified subset.
/// If it returns Err(), at least one of x and y is not in the disjoint-set.
pub fn union(&mut self, x: T, y: T) -> Result<usize, ()> {
let x_root;
let y_root;
let x_rank;
let y_rank;
match self.find(x) {
Some(x_r) => {
x_root = x_r;
x_rank = self.rank[x_root];
}
None => {
return Err(());
}
}
match self.find(y) {
Some(y_r) => {
y_root = y_r;
y_rank = self.rank[y_root];
}
None => {
return Err(());
}
}
// Implements union-by-rank optimization.
if x_root == y_root {
return Ok(x_root);
}
if x_rank > y_rank {
self.parent[y_root] = x_root;
return Ok(x_root);
} else {
self.parent[x_root] = y_root;
if x_rank == y_rank {
self.rank[y_root] += 1;
}
return Ok(y_root);
}
}
/// Forces all laziness, updating every tag.
pub fn finalize(&mut self) {
for i in 0..self.set_size {
DisjointSet::<T>::find_internal(&mut self.parent, i);
}
}
}
I think you're just not extracting the information out of your DisjointSet struct correctly.
I got sniped by this and implemented union find. First, with a basic usize implemention:
pub struct UnionFinderImpl {
parent: Vec<usize>,
}
Then with a wrapper for more generic types:
pub struct UnionFinder<T: Hash> {
rev: Vec<Rc<T>>,
fwd: HashMap<Rc<T>, usize>,
uf: UnionFinderImpl,
}
Both structs implement a groups() method that returns a Vec<Vec<>> of groups. Clone isn't required because I used Rc.
Playground
Here's where I'm starting from:
#[derive(PartialEq)]
enum ControlItem {
A {
name: &'static str,
},
B {
name: &'static str,
},
}
struct Control {
items: Vec<(ControlItem, bool)>,
}
impl Control {
pub fn set(&mut self, item: ControlItem, is_ok: bool) {
match self.items.iter().position(|ref x| (**x).0 == item) {
Some(idx) => {
self.items[idx].1 = is_ok;
}
None => {
self.items.push((item, is_ok));
}
}
}
pub fn get(&self, item: ControlItem) -> bool {
match self.items.iter().position(|ref x| (**x).0 == item) {
Some(idx) => return self.items[idx].1,
None => return false,
}
}
}
fn main() {
let mut ctrl = Control { items: vec![] };
ctrl.set(ControlItem::A { name: "a" }, true);
assert_eq!(ctrl.get(ControlItem::A { name: "a" }), true);
ctrl.set(ControlItem::B { name: "b" }, false);
assert_eq!(ctrl.get(ControlItem::B { name: "b" }), false);
}
I have a Control type that should save the state of some predefined items and report it back to user.
I have a virtual table in my mind, like this:
|Name in program | Name for user |
|item_1 | Item one bla-bla |
|item_2 | Item two bla-bla |
|item_3 | Item three another-bla-bla|
I want Control to have get / set methods that accept only things with names item_1, item_2, item_3.
I want to hold this virtual table in two crates: "main" and "platform". Most of the implementation of Control should be in the main crate, and definitions of the items (like item_3) should go into the platform crate. I want to register item_3 at compile time.
Any ideas on how achieve this?
It sounds like you should use a trait, not an enum. You could define a trait and implement it like this:
pub trait ControlItem {
fn name(&self) -> &str;
}
struct A(&'static str);
impl ControlItem for A {
fn name(&self) -> &str {
self.0
}
}
// ... similar struct and impl blocks for other items
Then these structs can be moved into separate crates.
You'd need to change Control to store a Vec<(Box<ControlItem>, bool)>, and either change get and set to take a Box<ControlItem>, or to be generic over T: ControlItem.
Read about traits and trait objects for more.