How to build a HashMap of Vectors in Rust? - rust

I'm a Rust newbie. I'm trying to represent a directed graph's adjacency list as a HashMap of char {vertex name} to Vector of (char,int) {vertex name, cost}. I want the final HashMap to be immutable, but I'd like to build up the vector and then not need to make a copy of it to make it immutable.
My code is below. At the indicated line I get "cannot borrow immutable dereference (dereference is implicit, due to indexing) as mutable". This makes sense, as the Vec<(char,int)> in the map is not mutable. But I'm not sure how to fix it.
Is there a way to do this in Rust?
pub struct Edge {
to: char,
from: char,
weight: int
}
pub struct digraph {
_vertices: Vec<char>,
_adj_list: HashMap<char, Vec<(char,int)> >
}
impl digraph {
pub fn new(nodes: &Vec<char>, edges: &Vec<Edge> ) -> Option<digraph> {
let mut tmp_adj_list = HashMap::new();
for node in (*nodes).iter() {
tmp_adj_list.insert(*node, Vec::new());
}
for edge in (*edges).iter() {
let Edge{ to: to, from:from, weight:weight } = *edge;
if !(*nodes).contains(&to) | !(*nodes).contains(&from) {
return None;
}
tmp_adj_list[from].push((to,weight)) // *********** error here
}
Some(digraph { _vertices: (*nodes).clone(), _adj_list: tmp_adj_list })
}
}

Taking [] onto a HashMap is sugar for the (now deprecated) get(..) function, which declaration is :
fn get<'a>(&'a self, k: &K) -> &'a V
and returns a constant (&) reference. But the push(..) method of Vec expects a &mut reference, hence the error.
What you need is the get_mut(..) method of HashMap, which returns a &mut reference to the value.
Also, some minor points:
when calling a method, dereference is automatic : (*foo).bar() is exactly the same as foo.bar()
you can dereference automatically in your loop with for &edge in edges.iter() {...}
Including all this, your function becomes :
impl digraph {
pub fn new(nodes: &Vec<char>, edges: &Vec<Edge> ) -> Option<digraph> {
let mut tmp_adj_list = HashMap::new();
for &node in nodes.iter() {
tmp_adj_list.insert(node, Vec::new());
}
for &edge in edges.iter() {
let Edge{ to: to, from:from, weight:weight } = edge;
if !nodes.contains(&to) | !nodes.contains(&from) {
return None;
}
tmp_adj_list.get_mut(&from).push((to,weight))
}
Some(digraph { _vertices: nodes.clone(), _adj_list: tmp_adj_list })
}
}

Related

Temporarily cache owned value between iterator adapters

I'd like to know if there's a way to cache an owned value between iterator adapters, so that adapters later in the chain can reference it.
(Or if there's another way to allow later adapters to reference an owned value that lives inside the iterator chain.)
To illustrate what I mean, let's look at this (contrived) example:
I have a function that returns a String, which is called in an Iterator map() adapter, yielding an iterator over Strings. I'd like to get an iterator over the chars() in those Strings, but the chars() method requires a string slice, meaning a reference.
Is this possible to do, without first collecting the Strings?
Here's a minimal example that of course fails:
fn greet(c: &str) -> String {
"Hello, ".to_owned() + c
}
fn main() {
let names = ["Martin", "Helena", "Ingrid", "Joseph"];
let iterator = names.into_iter().map(greet);
let fails = iterator.flat_map(<str>::chars);
}
Playground
Using a closure instead of <str>::chars - |s| s.chars() - does of course not work either. It makes the types match, but breaks lifetimes.
Edit (2022-10-03): In response to the comments, here's some pseudocode of what I have in mind, but with incorrect lifetimes:
struct IteratorCache<'a, T, I>{
item : Option<T>,
inner : I,
_p : core::marker::PhantomData<&'a T>
}
impl<'a, T, I> Iterator for IteratorCache<'a, T,I>
where I: Iterator<Item=T>
{
type Item=&'a T;
fn next(&mut self) -> Option<&'a T> {
self.item = self.inner.next();
if let Some(x) = &self.item {
Some(&x)
} else {
None
}
}
}
The idea would be that the reference could stay valid until the next call to next(). However I don't know if this can be expressed with the function signature of the Iterator trait. (Or if this can be expressed at all.)
I don't think something like this exists yet, and collecting into a Vec<char> creates some overhead, but you can write such an iterator yourself with a little bit of trickery:
struct OwnedCharsIter {
s: String,
index: usize,
}
impl OwnedCharsIter {
pub fn new(s: String) -> Self {
Self { s, index: 0 }
}
}
impl Iterator for OwnedCharsIter {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
// Slice of leftover characters
let slice = &self.s[self.index..];
// Iterator over leftover characters
let mut chars = slice.chars();
// Query the next char
let next_char = chars.next()?;
// Compute the new index by looking at how many bytes are left
// after querying the next char
self.index = self.s.len() - chars.as_str().len();
// Return next char
Some(next_char)
}
}
fn greet(c: &str) -> String {
"Hello, ".to_owned() + c
}
fn main() {
let names = ["Martin", "Helena", "Ingrid", "Joseph"];
let iterator = names.into_iter().map(greet);
let chars_iter = iterator.flat_map(OwnedCharsIter::new);
println!("{:?}", chars_iter.collect::<String>())
}
"Hello, MartinHello, HelenaHello, IngridHello, Joseph"

impl push(self , item : T) for a struct with 2 Vecs<T>

I've been trying to impl the push for this struct:
struct StackMin<T: std::cmp::Ord>
{
stack : Vec<T>,
min : Vec<T>
}
like this:
fn push(&mut self, item: T) {
let l = self.stack.len();
let x: T;
match l {
0 => println!("There is nothing in the stack."),
n => {
if item <= self.stack[l - 1] {
self.stack.push(item); //item moved here
self.min.push(item); // so I can't use it again here
} else {
self.stack.push(item);
}
}
}
}
The problem is item moves with the first Vec<T>::push so I can't use it immediately at the second call of push(). I thought about making a variable let a = &item and use it in the second call, but push requires "T" and not "&T".
Also, if I try to do a=self.stack[l-1], it's an error because the T type doesn't have the Copy/Clone traits.
LATER EDIT: I also need to print the last value from the min Vector. But it doesn't have the std::fmt::Display , and I don't think it can be impl!? Any ideas?
How would you approach this?
Assuming you can change the inner values of the struct StackMin, but not the trait requirements, you could do something like this:
struct MinStack<T: std::cmp::Ord> {
// T is the data you want to store
// and usize points to the smallest T
inner: Vec<(T, usize)>
}
impl<T: std::cmp::Ord> MinStack<T> {
fn push(&mut self, val: T) {
let min_index = self.inner.last()
// get last min value and its index
.map(|(_, index)| (&self.inner[*index].0, index))
// check if it is smaller then the current value
.and_then(|(prev_min, min_index)|
(prev_min < &val).then(|| *min_index)
)
// if not smaller or does not exist
// set it to the current index
.unwrap_or(self.inner.len());
self.inner.push((val, min_index));
}
}
Here is a full implementation of the MinStack challenge Rust Playground.
Let me know if i should clarify something in the above code.
Docs for the used methods:
Vec::last
bool::then
Option::map
Option::and_then
Option::unwrap_or

Storing an iterator for a HashMap in a struct

Edit
As it seemms from the suggested solution, What I'm trying to achieve seems impossible/Not the correct way, therefore - I'll explain the end goal here:
I am parsing the values for Foo from a YAML file using serde, and I would like to let the user get one of those stored values from the yaml at a time, this is why I wanted to store an iterator in my struct
I have two struct similar to the following:
struct Bar {
name: String,
id: u32
}
struct Foo {
my_map: HashMap<String, Bar>
}
In my Foo struct, I wish to store an iterator to my HashMap, so a user can borrow values from my map on demand.
Theoretically, the full Foo class would look something like:
struct Foo {
my_map: HashMap<String, Bar>,
my_map_iter: HashMap<String, Bar>::iterator
}
impl Foo {
fn get_pair(&self) -> Option<(String, Bar)> {
// impl...
}
}
But I can't seem to pull it off and create such a variable, no matter what I try (Various compilation errors which seems like I'm just trying to do that wrong).
I would be glad if someone can point me to the correct way to achieve that and if there is a better way to achieve what I'm trying to do - I would like to know that.
Thank you!
I am parsing the values for Foo from a YAML file using serde
When you parse them you should put the values in a Vec instead of a HashMap.
I imagine the values you have also have names which is why you thought a HashMap would be good. You could instead store them like so:
let parsed = vec![]
for _ in 0..n_to_parse {
// first item of the tuple is the name second is the value
let key_value = ("Get from", "serde");
parsed.push(key_value);
}
then once you stored it like so it will be easy to get the pairs from it by keeping track of the current index:
struct ParsedHolder {
parsed: Vec<(String, String)>,
current_idx: usize,
}
impl ParsedHolder {
fn new(parsed: Vec<(String, String)>) -> Self {
ParsedHolder {
parsed,
current_idx: 0,
}
}
fn get_pair(&mut self) -> Option<&(String, String)> {
if let Some(pair) = self.parsed.get(self.current_idx) {
self.current_idx += 1;
Some(pair)
} else {
self.current_idx = 0;
None
}
}
}
Now this could be further improved upon by using VecDeque which will allow you to efficiently take out the first element of parsed. Which will make it easy to not use clone. But this way you will be only able to go through all the parsed values once which I think is actually what you want in your use case.
But I'll let you implement VecDeque 😃
The reason why this is a hard is that unless we make sure the HashMap isn't mutated while we iterate we could get into some trouble. To make sure the HashMap is immutable until the iterator lives:
use std::collections::HashMap;
use std::collections::hash_map::Iter;
struct Foo<'a> {
my_map: &'a HashMap<u8, u8>,
iterator: Iter<'a, u8, u8>,
}
fn main() {
let my_map = HashMap::new();
let iterator = my_map.iter();
let f = Foo {
my_map: &my_map,
iterator: iterator,
};
}
If you can make sure or know that the HashMap won't have new keys or keys removed from it (editing values with existing keys is fine) then you can do this:
struct Foo {
my_map: HashMap<String, String>,
current_idx: usize,
}
impl Foo {
fn new(my_map: HashMap<String, String>) -> Self {
Foo {
my_map,
current_idx: 0,
}
}
fn get_pair(&mut self) -> Option<(&String, &String)> {
if let Some(pair) = self.my_map.iter().skip(self.current_idx).next() {
self.current_idx += 1;
Some(pair)
} else {
self.current_idx = 0;
None
}
}
fn get_pair_cloned(&mut self) -> Option<(String, String)> {
if let Some(pair) = self.my_map.iter().skip(self.current_idx).next() {
self.current_idx += 1;
Some((pair.0.clone(), pair.1.clone()))
} else {
self.current_idx = 0;
None
}
}
}
This is fairly inefficient though because we need to iterate though the keys to find the next key each time.

Trouble chaining option and struct field using iterator interface

I'm trying to make the following code work:
struct IntHolder {
ints: Vec<i32>,
}
impl IntHolder {
fn special_int(&self) -> Option<i32> {
return None;
}
fn all_ints(&self) -> impl Iterator<Item=&i32> {
return self.special_int().iter().chain(self.ints.iter());
}
}
fn main() {
let tst = IntHolder{ints: vec![0, 1, 2]};
for o in tst.all_ints() {
println!("{}", o)
}
}
But I get this error:
|
10 | return self.special_int().iter().chain(self.ints.iter());
| ------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| temporary value created here
Oddly enough, if I change the function call to just inline None instead of calling the function that returns an option, it works:
struct IntHolder {
ints: Vec<i32>,
}
impl IntHolder {
fn special_int(&self) -> Option<i32> {
return None;
}
fn all_ints(&self) -> impl Iterator<Item=&i32> {
return None.iter().chain(self.ints.iter());
}
}
fn main() {
let tst = IntHolder{ints: vec![0, 1, 2]};
for o in tst.all_ints() {
println!("{}", o)
}
}
Does anyone know how to make this work, or why it only seems to break when I call a function to generate the option?
(This is toy code to illustrate the problem I'm having. In my actual code, I have a struct which holds a vector of objects, and also sometimes has a special object that can be computed from the other fields. I want to return an iterator that iterates over the special object if it can be computed, and then iterates over all the objects in the vector. I'd also like to avoid having to do heap allocations if I can.)
The problem is that iter takes a reference to the value rather than consuming it, returning an iterator that references a value that belongs to the function.
Try using into_iter() instead:
return self.special_int().into_iter().chain(self.ints.iter());

How do I automatically clear an attribute in a struct when it is moved?

I have a struct
struct Test {
list: Vec<u64>
}
and method in which I would like to get vector and erase list field to empty Vec
fn get_list(&self) -> Vec<u64> {
let list = Vec::new();
for item in self.list.drain() {
list.push(item);
}
list
}
It there another approach for doing it? Something like autoreinit field on moving value, for example:
fn get_list(&self) -> ???<Vec<u64>> {
self.list
}
Here is the solution, you can test on Rust playground (sadly share button doesn't work for me atm).
use std::mem;
#[derive(Debug)]
struct Test {
list: Vec<u64>
}
impl Test {
fn get_list(&mut self) -> Vec<u64> {
let repl = mem::replace(&mut self.list, Vec::new());
repl
}
}
fn main() {
let mut r = Test {
list : vec![1,2,3]
};
print!("r : {:?} ", r);
print!("replace : {:?} ", r.get_list());
print!("r : {:?} ", r);
}
You just need to run mem::replace(docs) on a mutable value and replace it with a value that will be moved in its place. In this case our destination is self.list and value we are replacing it is a blank Vec.
Things to note:
Field self.list of Test, needs to be taken as &mut self.list.
Previous change implies that self should be mutable as well.
Second parameter of replace is moved. That means it won't be available for further after this call. What this usually means, you either pass it a Vec constructor (e.g. Vec::new()) or clone of value that's replacing.
From #rust IRC
< theme> jiojiajiu, http://doc.rust-lang.org/nightly/std/mem/fn.replace.html

Resources