I'd like to write a generic function that can make all unique vectors where each index has a series of values.
Easiest to illustrate with an example.
for i in (1..3).combinations_with_replacement(3) {
println!("{:?}",i);
}
Produces the ouput
[1, 1, 1]
[1, 1, 2]
[1, 2, 2]
[2, 2, 2]
Which is not satisfactory because it's missing members like
[1, 2, 1]
[2, 1, 2]
[2, 2, 1]
So I also tried permutations(3) but since their are more positions than items in the iterator, the iterator is empty. There also doesn't appear to be a permutations_with_replacement but maybe that'd be the name of the function I'm looking for.
In this case you could accomplish the task with 3 nested for loops but this is ugly and not a general solution. I think a recursive backtracking solution could do it too but seems like their should be something in itertools that I'm missing.
Here's another example of what I want but with code written a few languages that aren't rust.
Using itertools, based on #Ry-'s suggestion:
for i in (1..=3).map(|_| 1..=2).multi_cartesian_product() {
println!("{i:?}");
}
Output:
[1, 1, 1]
[1, 1, 2]
[1, 2, 1]
[1, 2, 2]
[2, 1, 1]
[2, 1, 2]
[2, 2, 1]
[2, 2, 2]
Playground
I'm not sure how this can be done using itertools, but here is one way to achieve the same result in plain Rust.
pub struct PermutationsReplacementIter<I> {
items: Vec<I>,
permutation: Vec<usize>,
group_len: usize,
finished: bool,
}
impl<I: Copy> PermutationsReplacementIter<I> {
fn increment_permutation(&mut self) -> bool {
let mut idx = 0;
loop {
if idx >= self.permutation.len() {
return true;
}
self.permutation[idx] += 1;
if self.permutation[idx] >= self.items.len() {
self.permutation[idx] = 0;
idx += 1;
} else {
return false;
}
}
}
fn build_vec(&self) -> Vec<I> {
let mut vec = Vec::with_capacity(self.group_len);
for idx in &self.permutation {
vec.push(self.items[*idx]);
}
vec
}
}
impl<I: Copy> Iterator for PermutationsReplacementIter<I> {
type Item = Vec<I>;
fn next(&mut self) -> Option<Self::Item> {
if self.finished {
return None;
}
let item = self.build_vec();
if self.increment_permutation() {
self.finished = true;
}
Some(item)
}
}
pub trait ToPermutationsWithReplacement {
type Iter;
fn permutations_with_replacement(self, group_len: usize) -> Self::Iter;
}
impl<I: Iterator> ToPermutationsWithReplacement for I {
type Iter = PermutationsReplacementIter<<I as Iterator>::Item>;
fn permutations_with_replacement(self, group_len: usize) -> Self::Iter {
let items = self.collect::<Vec<_>>();
PermutationsReplacementIter {
permutation: vec![0; group_len],
group_len,
finished: group_len == 0 || items.len() == 0,
items,
}
}
}
Then it can be used similarly to combinations_with_replacement.
for x in (1..3).permutations_with_replacement(3) {
println!("{:?}", x);
}
// Output:
[1, 1, 1]
[2, 1, 1]
[1, 2, 1]
[2, 2, 1]
[1, 1, 2]
[2, 1, 2]
[1, 2, 2]
[2, 2, 2]
Playground Link
You can also put it on any iterator where the elements implement Copy. However, I wouldn't recommend it. The time complexity for this task is extremely bad. For an input iterator of n elements in groups of length m, this will create an iterator of about n^m items assuming my math is correct.
Related
Rust does not allow borrowing multiple mutable references. I understand that. But I can not find any elegant way to implement a few algorithms. Below is a simplified version of one such algorithm. The Ladder struct hands out slices of ever increasing sequence of numbers, such as, [0], [0, 1], [0, 1, 2] and so on.
struct Ladder {
position: usize,
data: [u8; 10],
}
impl Ladder {
fn get_next(&mut self) -> &[u8] {
self.position += 1;
&(self.data[0..self.position])
}
fn new() -> Ladder {
Ladder {
position: 0,
data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
}
}
}
I need to call get_next() a couple of times, collect the returned sequences and call a closure that will do something with those sequences.
fn test_ladder(consumer: impl Fn(&[&[u8]])) {
let mut l = Ladder::new();
let mut steps: [&[u8]; 3] = [&[]; 3];
steps[0] = l.get_next();
steps[1] = l.get_next();
steps[2] = l.get_next();
consumer(&steps);
}
fn main() {
test_ladder(|steps| {
for seq in steps {
println!("{:?}", *seq);
}
});
}
It is a non-allocating algorithm. I can not use std::Vec.
What is the idiomatic way to approach problems like this?
The problem here is that you can't keep references to something that you mutate, and .get_next() is allowed to mutate data. What you need to do is separate the data from the mutation. You can do that by only keeping a reference to the original data.
Creating a sequence of elements sounds a lot like an iterator, so here's an example:
struct LadderIter<'a> {
position: usize,
data: &'a [u8],
}
impl<'a> LadderIter<'a> {
fn new(data: &'a [u8]) -> LadderIter<'a> {
LadderIter { position: 0, data }
}
}
impl<'a> Iterator for LadderIter<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<Self::Item> {
if self.position == self.data.len() {
None
} else {
self.position += 1;
Some(&self.data[0..self.position])
}
}
}
Which you can then use as an iterator:
for step in LadderIter::new(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) {
println!("{step:?}");
}
[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Or in your specific use-case:
let data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let mut ladder = LadderIter::new(&data);
let steps: [&[u8]; 3] = [
ladder.next().unwrap(),
ladder.next().unwrap(),
ladder.next().unwrap(),
];
Another approach is to use interior mutability. Since you are only modifying position, you can use the zero-cost Cell:
use std::cell::Cell;
struct Ladder {
position: Cell<usize>,
data: [u8; 10],
}
impl Ladder {
fn get_next(&self) -> &[u8] {
self.position.set(self.position.get() + 1);
&self.data[0..self.position.get()]
}
fn new() -> Ladder {
Ladder {
position: Cell::new(0),
data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
}
}
}
code first:
use std::collections::HashMap;
macro_rules! arr{
([$($t:expr=>[$($c:expr),*]),*]) => {
vec![
$({
let mut m = HashMap::new();
m.insert($t, vec![$($c),*]);
m
}),*
]
};
}
fn main() {
let a = arr!([
"A"=>[1,2,3],
"B"=>[3,4]
]);
println!("{:?}", a);
//print: [{"A": [1, 2, 3]}, {"B": [3, 4]}]
}
I have above macro to generate a vec, contains several HashMap, in which these HashMap value is a vec as well,
{"A": [1, 2, 3]} => vec value length: 3,
{"B": [3, 4]} => vec value length: 2,
I wanna all the HashMap have the same length,
how to write in the macro to control this?
You can change the macro so that it creates a block (second set of {} encapsulating the macro definition) that you can set helper variables in and do a second pass over your vector, resizing anything that is smaller than the largest array.
In this case I've resized the arrays with the default value of the type to keep it simple. You may wish to wrap the data in Some().
This:
use std::cmp;
use std::collections::HashMap;
use std::default::Default;
macro_rules! arr{
([$($t:expr=>[$($c:expr),*]),*]) => {{
let mut max = 0;
let mut result = vec![
$({
let mut m = HashMap::new();
m.insert($t, vec![$($c),*]);
// Simply unwrap here as we know we inserted at this key above
max = cmp::max(max, m.get($t).unwrap().len());
m
}),*
];
for m in result.iter_mut() {
for v in m.values_mut() {
if v.len() < max {
v.resize_with(max, Default::default);
}
}
}
result
}};
}
fn main() {
let a = arr!([
"A"=>[1,2,3],
"B"=>[3,4]
]);
println!("{:?}", a);
//print: [{"A": [1, 2, 3]}, {"B": [3, 4]}]
}
Yields:
[{"A": [1, 2, 3]}, {"B": [3, 4, 0]}]
I'm getting this error
error[E0502]: cannot borrow `counts` as immutable because it is also borrowed as mutable
--> src/main.rs:13:64
|
13 | counts.entry(x).or_insert(cmp::max(current_count, *counts.get(&x).unwrap()));
| --------------- --------- ^^^^^^^^^^^^^^ immutable borrow occurs here
| | |
| | mutable borrow later used by call
| mutable borrow occurs here
but I can't seem to understand what's wrong despite having seen a few other questions asking about the same error and they are using slice instead of dealing with a HashMap like here.
The 2nd argument of cmp::max has to be a value, but I cant figure out how to make use of an mutable borrow here as suggested by the compiler.
use std::collections::HashMap;
use std::cmp;
fn main() {
let data: Vec<u8> = vec![1,1,3,1,1];
let mut counts = HashMap::new();
let mut current_count = 0;
for (i, &x) in data.iter().enumerate() {
if i > 0 {
if x == data[i-1] {
current_count += 1;
counts.entry(x).or_insert(cmp::max(current_count, *counts.get(&x).unwrap()));
} else {
current_count = 0;
}
}
}
println!("{:?}", counts);
}
#BallpointBen I think this might work, but not sure if this is a good way.
for (i, &x) in data.iter().enumerate() {
if i > 0 {
if x == data[i-1] {
current_count += 1;
counts.entry(x).or_insert(1);
counts.insert(x, cmp::max(current_count, counts[&x]));
} else {
current_count = 0;
}
}
}
HashMap::entry() borrows the map mutably for the whole life of the returned Entry. You cannot use the map until you finish with the entry.
The fix is simple - first retrieve the value into a variable, then call entry():
let v = *counts.get(&x).unwrap();
counts
.entry(x)
.or_insert(cmp::max(current_count, v));
You cannot use or_insert_with() by that, which would be preferred, but you didn't use it anyway.
However, what you're trying to do is not good: when will your or_insert() be needed? Only when there is no value associated with this key in the map, so trying to get().unwrap() it is always going to panic!
Here is a solution that meshes well with the type system. We append a None to the end of the iterator to signal that we're done (roughly equivalent to an if i == my_vec.len()-1 check but without needing a Vec)
use std::collections::HashMap;
use std::hash::Hash;
fn longest_run<T: Hash + Eq>(items: impl IntoIterator<Item = T>) -> HashMap<T, usize> {
let mut runs = HashMap::new();
let mut items = items.into_iter();
let mut prev = match items.next() {
Some(x) => x,
None => return runs,
};
let mut curr_count = 1;
for item in items.map(Some).chain(std::iter::once(None)) {
if let Some(item) = item {
if item == prev {
curr_count += 1;
} else {
let prev_count = runs.entry(prev).or_insert(1);
*prev_count = (*prev_count).max(curr_count);
curr_count = 1;
}
prev = item;
} else {
let prev_count = runs.entry(prev).or_insert(1);
*prev_count = (*prev_count).max(curr_count);
// Redundant, but needed to tell the compiler it's
// ok to move prev into `entry` without
// reinitializing it, as we won't need it again
break;
}
}
runs
}
fn main() {
for v in vec![
vec![],
vec![1],
vec![1, 1, 1, 1, 1],
vec![1, 2],
vec![1, 1, 2, 1],
vec![1, 1, 2, 1, 1, 1, 1, 2, 2, 2],
vec![1, 1, 1, 1, 1, 2, 3, 1, 1, 2, 2, 3, 3],
] {
println!("{:?}: {:?}", v, longest_run(v.iter().copied()));
}
}
Prints
[]: {}
[1]: {1: 1}
[1, 1, 1, 1, 1]: {1: 5}
[1, 2]: {2: 1, 1: 1}
[1, 1, 2, 1]: {1: 2, 2: 1}
[1, 1, 2, 1, 1, 1, 1, 2, 2, 2]: {2: 3, 1: 4}
[1, 1, 1, 1, 1, 2, 3, 1, 1, 2, 2, 3, 3]: {2: 2, 3: 2, 1: 5}
Given a vector of vectors of some value T, ie. Vec<Vec<T>>.
What's the idiomatic way to check if the inner vectors have the same length? (without external dependencies)
That is, true if all the inner vectors have the same length, and false otherwise.
You can use the all method to check if all elements of an iterator match a predicate. Then just compare against the first element in the list.
fn main() {
let vec_of_vecs = vec![
vec![1, 2, 3],
vec![1, 2, 3],
vec![1, 2, 3],
vec![1, 2, 3],
vec![1, 2, 3],
vec![1, 2, 3, 4], // remove this to prove that it works for both cases
];
let all_same_length = vec_of_vecs
.iter()
.all(|ref v| v.len() == vec_of_vecs[0].len());
if all_same_length {
println!("They're all the same");
} else {
println!("They are not the same");
}
}
An other solution more generic and idiomatic in my opinion:
fn all_eq_len<'a, T, E: 'a>(collection: T) -> bool
where
T: IntoIterator<Item = &'a Vec<E>>,
{
let mut iter = collection.into_iter();
if let Some(first) = iter.next() {
let len = first.len();
iter.all(|v| v.len() == len)
} else {
true
}
}
And of course using itertools:
use itertools::Itertools;
vec_of_vecs.iter().map(|v| v.len()).all_equal()
Given a vector of vectors of some value T, ie. Vec<Vec<T>>.
What's the idiomatic way to check if the inner vectors have the same length? (without external dependencies)
That is, true if all the inner vectors have the same length, and false otherwise.
You can use the all method to check if all elements of an iterator match a predicate. Then just compare against the first element in the list.
fn main() {
let vec_of_vecs = vec![
vec![1, 2, 3],
vec![1, 2, 3],
vec![1, 2, 3],
vec![1, 2, 3],
vec![1, 2, 3],
vec![1, 2, 3, 4], // remove this to prove that it works for both cases
];
let all_same_length = vec_of_vecs
.iter()
.all(|ref v| v.len() == vec_of_vecs[0].len());
if all_same_length {
println!("They're all the same");
} else {
println!("They are not the same");
}
}
An other solution more generic and idiomatic in my opinion:
fn all_eq_len<'a, T, E: 'a>(collection: T) -> bool
where
T: IntoIterator<Item = &'a Vec<E>>,
{
let mut iter = collection.into_iter();
if let Some(first) = iter.next() {
let len = first.len();
iter.all(|v| v.len() == len)
} else {
true
}
}
And of course using itertools:
use itertools::Itertools;
vec_of_vecs.iter().map(|v| v.len()).all_equal()