Rust: Map two Vecs into a third Vec of composite structs - rust

I have three structs:
struct A;
struct B;
struct C {
a: Option<A>,
b: Option<B>
}
Given inputs Vec<A> and Vec<B> and some predicate function, I want to create an output Vec<C>, which is a combination of the elements of the inputs, something like the following:
let aVec: Vec<A> = vec![];
let bVec: Vec<B> = vec![];
let mut cVec: Vec<C> = vec![];
for a in aVec {
if let Some(b) = bVec.into_iter().find(predicate) {
cVec.push(C{a: Some(a), b: Some(b)});
}
}
Is there a way to do this without needing B to be copyable? Both input vectors aren't required after the operation. Also, is this possible without the loop?

You can:
Find the index of the element satisfying predicate. (I would use Iterator::position.)
remove or swap_remove the element at the position obtained by the previous step.
push the previously removed element into result.
In code:
use itertools; // 0.8.2
use itertools::Itertools;
struct A {}
struct B {
n: usize,
}
struct C {
a: Option<A>,
b: Option<B>
}
fn main() {
let aVec: Vec<A> = vec![];
let mut bVec: Vec<B> = vec![];
let mut cVec: Vec<C> = vec![];
for a in aVec {
if let Some(idx) = bVec.iter()
.position(|b| b.n==42)
{
let b = bVec.remove(idx); // or swap_remove if ordering does not need to be preserved
cVec.push(C{a: Some(a), b: Some(b)});
}
}
}

Related

Problems trying to get intersection of a Vector

I am having a problem whilst trying to get the intersection of two Vectors.
impl Solution {
pub fn intersection(nums: Vec<Vec<i32>>) -> Vec<i32> {
// Intended strategy:
// Store the first element into an intersect_result
// Iterate over the remaining elements for each element:
// Determine the intersection of the current element and the intersect result
// set intersect result to this.
// Sort the intersect result
// Return the intersect result back to the caller.
let len:i32 = nums.len() as i32;
let intersect_result:Vec<i32> = nums[0].clone();
for i in 1..len{
println!("i is: {}", i);
let temp_vec:Vec<i32> = nums[i as usize].clone();
// find the intersection of the current element with the intersect result
let unique_a:HashSet<i32> = temp_vec.into_iter().collect();
let unique_b:HashSet<i32> = intersect_result.clone().into_iter().collect();
intersect_result = unique_a.intersection(&unique_b).collect::<Vec<_>>();
}
vec![]
}
}
The error message I get is:
= note: expected struct `Vec<i32>`
found struct `Vec<&i32>`
This happens in the call unique_a.intersection().
Any thoughts guys?
You can add a map(|i| *i) in the iterator chain that causes the error:
intersect_result = unique_a.intersection(&unique_b).map(|i| *i).collect::<Vec<_>>();
When fixing this, the code also seems to work as intended. I think there are a few improvements possible (probably more, but these immediately tracked my attention):
use hashbrown::HashSet;
pub fn intersection(nums: Vec<Vec<i32>>) -> Vec<i32> {
let mut intersect_result: Vec<i32> = nums[0].clone();
for temp_vec in nums {
let unique_a: HashSet<i32> = temp_vec.into_iter().collect();
intersect_result = unique_a
.intersection(&intersect_result.into_iter().collect())
.map(|i| *i)
.collect::<Vec<_>>();
}
intersect_result
}
fn main() {
let a = vec![1, 2, 3];
let b = vec![2, 3, 4];
let c = vec![3, 4, 5];
let v = vec![a, b, c];
let res = intersection(v);
println!("res: {:?}", res);
}

Proptest: Strategy to generate vectors of vectors

I want to generate DAGs with proptest. The algorithm that I pick would be this. I've written the plain algorithm below -- but I need help transforming this to a proptest strategy.
What would a strategy need to look like that did the same as the below code but without using a random number generator? (It goes without saying that random number generators are bad for property-based testing.)
Standard code without proptest strategy:
(https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2de4a757a96d123bf83b5157e0633d33)
use rand::Rng;
fn main() {
println!("{:?}", random_vec_of_vec());
}
fn random_vec_of_vec() -> Vec<Vec<u16>> {
const N: u16 = 30;
const K: usize = 3;
let mut rng = rand::thread_rng();
let length: u16 = rng.gen_range(0, N);
let mut outer = vec![];
for index in 1..length {
let mut inner = vec![0u16; rng.gen_range(0, K)];
for e in &mut inner {
*e = rng.gen_range(0, index);
}
// De-duplicate elements. Particularly a problem with `index < K`.
inner.sort();
inner.dedup();
outer.push(inner);
}
outer
}
Previous work
I tried using the vec function, but I would need to nest two vec functions. And, the inner vec function could only generate values up to the index in the outer vector.
use proptest::collection::vec;
// INDEX should be the value of the position of the inner vector
// in the outer vector. How could the be found?
let strategy = vec(vec(1..INDEX, 0..K), 0..N);
The index method is not helpful because the right size would still not be known.
One way to go about this, is to replace each rng.gen_range() call with a strategy. Nested strategies must then be connected with prop_flat_map.
In the below code, I replaced my pattern
let length = rng.gen_range(0, N); for i in 1..length { .. }, with a new function vec_from_length(length: usize), which returns a Strategy.
#[cfg(test)]
mod tests {
use super::*;
use proptest::collection::hash_set;
use proptest::prelude::*;
use std::collections::HashSet;
proptest! {
#[test]
fn meaningless_test(v in vec_of_vec()) {
let s = sum(&v); // sum of the sum of all vectors.
prop_assert!(s < 15);
}
}
fn vec_of_vec() -> impl Strategy<Value = Vec<Vec<u16>>> {
const N: u16 = 10;
let length = 0..N;
length.prop_flat_map(vec_from_length).prop_map(convert)
}
fn vec_from_length(length: u16) -> impl Strategy<Value = Vec<HashSet<u16>>> {
const K: usize = 5;
let mut result = vec![];
for index in 1..length {
// Using a hash_set instead of vec because the elements should be unique.
let inner = hash_set(0..index, 0..K);
result.push(inner);
}
result
}
/// Convert Vec<HashSet<T>> to Vec<Vec<T>>
fn convert(input: Vec<HashSet<u16>>) -> Vec<Vec<u16>> {
let mut output = vec![];
for inner in input {
output.push(inner.into_iter().collect())
}
output
}
}
One more thing: An impl Strategy<Value=Vec<T>> can be generated from either the vec function (a strategy of vector) or from a vector of strategies! In the above code, I do this through having result be pushed with hash_set(..) which is a Strategy. The type is thus something like Vec<Strategy<T>> not Strategy<Vec<T>> (pedantic: Strategy is not a type, maybe).

How can I return the combination of two borrowed RefCells?

I have a struct with two Vecs wrapped in RefCells. I want to have a method on that struct that combines the two vectors and returns them as a new RefCell or RefMut:
use std::cell::{RefCell, RefMut};
struct World {
positions: RefCell<Vec<Option<Position>>>,
velocities: RefCell<Vec<Option<Velocity>>>,
}
type Position = i32;
type Velocity = i32;
impl World {
pub fn new() -> World {
World {
positions: RefCell::new(vec![Some(1), None, Some(2)]),
velocities: RefCell::new(vec![None, None, Some(1)]),
}
}
pub fn get_pos_vel(&self) -> RefMut<Vec<(Position, Velocity)>> {
let mut poses = self.positions.borrow_mut();
let mut vels = self.velocities.borrow_mut();
poses
.iter_mut()
.zip(vels.iter_mut())
.filter(|(e1, e2)| e1.is_some() && e2.is_some())
.map(|(e1, e2)| (e1.unwrap(), e2.unwrap()))
.for_each(|elem| println!("{:?}", elem));
}
}
fn main() {
let world = World::new();
world.get_pos_vel();
}
How would I return the zipped contents of the vectors as a new RefCell? Is that possible?
I know there is RefMut::map() and I tried to nest two calls to map, but didn't succeed with that.
You want to be able to modify the positions and velocities. If these have to be stored in two separate RefCells, what about side-stepping the problem and using a callback to do the modification?
use std::cell::RefCell;
struct World {
positions: RefCell<Vec<Option<Position>>>,
velocities: RefCell<Vec<Option<Velocity>>>,
}
type Position = i32;
type Velocity = i32;
impl World {
pub fn new() -> World {
World {
positions: RefCell::new(vec![Some(1), None, Some(2)]),
velocities: RefCell::new(vec![None, None, Some(1)]),
}
}
pub fn modify_pos_vel<F: FnMut(&mut Position, &mut Velocity)>(&self, mut f: F) {
let mut poses = self.positions.borrow_mut();
let mut vels = self.velocities.borrow_mut();
poses
.iter_mut()
.zip(vels.iter_mut())
.filter_map(|pair| match pair {
(Some(e1), Some(e2)) => Some((e1, e2)),
_ => None,
})
.for_each(|pair| f(pair.0, pair.1))
}
}
fn main() {
let world = World::new();
world.modify_pos_vel(|position, velocity| {
// Some modification goes here, for example:
*position += *velocity;
});
}
If you want to return a new Vec, then you don't need to wrap it in RefMut or RefCell:
Based on your code with filter and map
pub fn get_pos_vel(&self) -> Vec<(Position, Velocity)> {
let mut poses = self.positions.borrow_mut();
let mut vels = self.velocities.borrow_mut();
poses.iter_mut()
.zip(vels.iter_mut())
.filter(|(e1, e2)| e1.is_some() && e2.is_some())
.map(|(e1, e2)| (e1.unwrap(), e2.unwrap()))
.collect()
}
Alternative with filter_map
poses.iter_mut()
.zip(vels.iter_mut())
.filter_map(|pair| match pair {
(Some(e1), Some(e2)) => Some((*e1, *e2)),
_ => None,
})
.collect()
You can wrap it in RefCell with RefCell::new, if you really want to, but I would leave it up to the user of the function to wrap it in whatever they need.

String join on strings in Vec in reverse order without a `collect`

I'm trying to join strings in a vector into a single string, in reverse from their order in the vector. The following works:
let v = vec!["a".to_string(), "b".to_string(), "c".to_string()];
v.iter().rev().map(|s| s.clone()).collect::<Vec<String>>().connect(".")
However, this ends up creating a temporary vector that I don't actually need. Is it possible to do this without a collect? I see that connect is a StrVector method. Is there nothing for raw iterators?
I believe this is the shortest you can get:
fn main() {
let v = vec!["a".to_string(), "b".to_string(), "c".to_string()];
let mut r = v.iter()
.rev()
.fold(String::new(), |r, c| r + c.as_str() + ".");
r.pop();
println!("{}", r);
}
The addition operation on String takes its left operand by value and pushes the second operand in-place, which is very nice - it does not cause any reallocations. You don't even need to clone() the contained strings.
I think, however, that the lack of concat()/connect() methods on iterators is a serious drawback. It bit me a lot too.
I don't know if they've heard our Stack Overflow prayers or what, but the itertools crate happens to have just the method you need - join.
With it, your example might be laid out as follows:
use itertools::Itertools;
let v = ["a", "b", "c"];
let connected = v.iter().rev().join(".");
Here's an iterator extension trait that I whipped up, just for you!
pub trait InterleaveExt: Iterator + Sized {
fn interleave(self, value: Self::Item) -> Interleave<Self> {
Interleave {
iter: self.peekable(),
value: value,
me_next: false,
}
}
}
impl<I: Iterator> InterleaveExt for I {}
pub struct Interleave<I>
where
I: Iterator,
{
iter: std::iter::Peekable<I>,
value: I::Item,
me_next: bool,
}
impl<I> Iterator for Interleave<I>
where
I: Iterator,
I::Item: Clone,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
// Don't return a value if there's no next item
if let None = self.iter.peek() {
return None;
}
let next = if self.me_next {
Some(self.value.clone())
} else {
self.iter.next()
};
self.me_next = !self.me_next;
next
}
}
It can be called like so:
fn main() {
let a = &["a", "b", "c"];
let s: String = a.iter().cloned().rev().interleave(".").collect();
println!("{}", s);
let v = vec!["a".to_string(), "b".to_string(), "c".to_string()];
let s: String = v.iter().map(|s| s.as_str()).rev().interleave(".").collect();
println!("{}", s);
}
I've since learned that this iterator adapter already exists in itertools under the name intersperse — go use that instead!.
Cheating answer
You never said you needed the original vector after this, so we can reverse it in place and just use join...
let mut v = vec!["a".to_string(), "b".to_string(), "c".to_string()];
v.reverse();
println!("{}", v.join("."))

Using the same iterator multiple times in Rust

Editor's note: This code example is from a version of Rust prior to 1.0 when many iterators implemented Copy. Updated versions of this code produce a different errors, but the answers still contain valuable information.
I'm trying to write a function to split a string into clumps of letters and numbers; for example, "test123test" would turn into [ "test", "123", "test" ]. Here's my attempt so far:
pub fn split(input: &str) -> Vec<String> {
let mut bits: Vec<String> = vec![];
let mut iter = input.chars().peekable();
loop {
match iter.peek() {
None => return bits,
Some(c) => if c.is_digit() {
bits.push(iter.take_while(|c| c.is_digit()).collect());
} else {
bits.push(iter.take_while(|c| !c.is_digit()).collect());
}
}
}
return bits;
}
However, this doesn't work, looping forever. It seems that it is using a clone of iter each time I call take_while, starting from the same position over and over again. I would like it to use the same iter each time, advancing the same iterator over all the each_times. Is this possible?
As you identified, each take_while call is duplicating iter, since take_while takes self and the Peekable chars iterator is Copy. (Only true before Rust 1.0 — editor)
You want to be modifying the iterator each time, that is, for take_while to be operating on an &mut to your iterator. Which is exactly what the .by_ref adaptor is for:
pub fn split(input: &str) -> Vec<String> {
let mut bits: Vec<String> = vec![];
let mut iter = input.chars().peekable();
loop {
match iter.peek().map(|c| *c) {
None => return bits,
Some(c) => if c.is_digit(10) {
bits.push(iter.by_ref().take_while(|c| c.is_digit(10)).collect());
} else {
bits.push(iter.by_ref().take_while(|c| !c.is_digit(10)).collect());
},
}
}
}
fn main() {
println!("{:?}", split("123abc456def"))
}
Prints
["123", "bc", "56", "ef"]
However, I imagine this is not correct.
I would actually recommend writing this as a normal for loop, using the char_indices iterator:
pub fn split(input: &str) -> Vec<String> {
let mut bits: Vec<String> = vec![];
if input.is_empty() {
return bits;
}
let mut is_digit = input.chars().next().unwrap().is_digit(10);
let mut start = 0;
for (i, c) in input.char_indices() {
let this_is_digit = c.is_digit(10);
if is_digit != this_is_digit {
bits.push(input[start..i].to_string());
is_digit = this_is_digit;
start = i;
}
}
bits.push(input[start..].to_string());
bits
}
This form also allows for doing this with much fewer allocations (that is, the Strings are not required), because each returned value is just a slice into the input, and we can use lifetimes to state this:
pub fn split<'a>(input: &'a str) -> Vec<&'a str> {
let mut bits = vec![];
if input.is_empty() {
return bits;
}
let mut is_digit = input.chars().next().unwrap().is_digit(10);
let mut start = 0;
for (i, c) in input.char_indices() {
let this_is_digit = c.is_digit(10);
if is_digit != this_is_digit {
bits.push(&input[start..i]);
is_digit = this_is_digit;
start = i;
}
}
bits.push(&input[start..]);
bits
}
All that changed was the type signature, removing the Vec<String> type hint and the .to_string calls.
One could even write an iterator like this, to avoid having to allocate the Vec. Something like fn split<'a>(input: &'a str) -> Splits<'a> { /* construct a Splits */ } where Splits is a struct that implements Iterator<&'a str>.
take_while takes self by value: it consumes the iterator. Before Rust 1.0 it also was unfortunately able to be implicitly copied, leading to the surprising behaviour that you are observing.
You cannot use take_while for what you are wanting for these reasons. You will need to manually unroll your take_while invocations.
Here is one of many possible ways of dealing with this:
pub fn split(input: &str) -> Vec<String> {
let mut bits: Vec<String> = vec![];
let mut iter = input.chars().peekable();
loop {
let seeking_digits = match iter.peek() {
None => return bits,
Some(c) => c.is_digit(10),
};
if seeking_digits {
bits.push(take_while(&mut iter, |c| c.is_digit(10)));
} else {
bits.push(take_while(&mut iter, |c| !c.is_digit(10)));
}
}
}
fn take_while<I, F>(iter: &mut std::iter::Peekable<I>, predicate: F) -> String
where
I: Iterator<Item = char>,
F: Fn(&char) -> bool,
{
let mut out = String::new();
loop {
match iter.peek() {
Some(c) if predicate(c) => out.push(*c),
_ => return out,
}
let _ = iter.next();
}
}
fn main() {
println!("{:?}", split("test123test"));
}
This yields a solution with two levels of looping; another valid approach would be to model it as a state machine one level deep only. Ask if you aren’t sure what I mean and I’ll demonstrate.

Resources