Pointer-like logic in Rust [closed] - pointers

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed last year.
Improve this question
I need to move n elements from one vec to another, say a and b, in a pop/push loop. The tricky part is the following:
if n > 0, I want to transfer n elements from a to b.
if n < 0, I want to transfer |n| elements from b to a.
n == 0 isn't considered/will never happen/doesn't really matter.
Obviously, I want to check the condition only once, at the begining, and not in every iteration of the pop/push loop.
In a dynamic, "unsafe" language like Python, I would do it like this (which I believe is a very common pattern):
if n > 0:
from_ = a # `from` is a keyword in Python
to = b
else:
from_ = b
to = a
# push/pop loop follows
# using the `from_` and `to` variables, not `a` and `b`
# ...
I cannot treat this problem in the same way in Rust, however, because the borrow checker does not allow it:
cannot borrow `*self` as mutable more than once at a time
I understand how the borrow checker works and why this isn't allowed. So, my question is, what is the Rustacean way to solve this?

Hard to know what's going wrong if you provide no code, and fail to include 9/10th of the error message.
A trivial implementation seems to work fine:
fn move_items<T>(n: i32, a: &mut Vec<T>, b: &mut Vec<T>) {
let (from, to) = if n > 0 {
(a, b)
} else {
(b, a)
};
for _ in 0..n.abs() {
to.push(from.pop().unwrap());
}
}
it works just as well using "imperative" assignments:
fn move_items<T>(n: i32, a: &mut Vec<T>, b: &mut Vec<T>) {
let (from, to);
if n > 0 {
from = a;
to = b;
} else {
from = b;
to = a;
}
for _ in 0..n.abs() {
to.push(from.pop().unwrap());
}
}

Maybe something like this:
let v1 = vec![77, 4, 33];
let v2 = vec![8, 41, 67, 33];
let (mut v_src, mut v_dest) = if condition { (v1, v2) } else { (v2, v1) };

Related

Comparing consecutive elements of a vector to find local extrema in an idiomatic way [duplicate]

This question already has an answer here:
Comparing every element in a vector with the next one
(1 answer)
Closed 5 months ago.
I want to find local maxima (and minima) in a vector. So for every entry in a vector I have to check if it is larger (smaller) than the one before it AND the one after it. So I have to access 3 consecutive elements and perform 2 comparisons.
The most simple way would be this:
let v: Vec<64>; // this will hold some numeric values.
for i in 1..v.len() - 2 {
if v[i-1] < v[i] && v[i] > v[i+1] { println!("maximum!"); }
if v[i-1] > v[i] && v[i] < v[i+1] { println!("minimum!"); }
}
But I want to learn more about Rust and find out if there is a more idiomatic way for this. I tried doing it with an iterator, but then I still need to access 3 different locations and the iterator doesn't know its position. Also: wouldn't I need 3 iterators?
I tried to circumvent this by defining 2 mutable variables which "remember" the previous two vector entries and then skipping the first 2 elements:
let v: Vec<64>; // this will hold some numeric values.
let mut two_before = v[0];
let mut one_before = v[1];
for el in v.into_iter.skip(2) {
check_if_middle_greatest(two_before, one_before, el); // i put the comparisons into this function.
two_before = one_before;
one_before = *el;
}
Now this works, but it is very ugly in my opinion and doesn't really feel smart. I was wandering if this could be made more idiomatic. More "rusty".
You could use .windows(3) or .array_windows::<3>(), once it is stabilized.
fn print_max_min(l: i32, m: i32, r: i32) {
if m > l && m > r {
println!("max");
} else if m < l && m < r {
println!("min");
} else {
println!("-");
}
}
fn main() {
let v = [1, 2, 3, 2, 1, 2, 3];
for el in v.windows(3) {
print_max_min(el[0], el[1], el[2]);
}
}
-
max
-
min
-

Why am I getting double reference to type when iterating over vector of references? [duplicate]

This question already has answers here:
What is an idiomatic way to collect an iterator of &T into a collection of Ts?
(2 answers)
Closed 12 months ago.
Consider following minimum reproducible. I have a vector of objects and I have a hashmap where each value is a vector of references to objects from the objects vector.
I then get a value from HashMap (which is a reference to vector of references) and I want to filter it so I get vector of references to objects. However, when I do iter-filter-collect, compiler claims that I am iterating over &&O (instead of &O I expect) and errors out.
I can "fix" that error by uncommenting the map function which dereferences iterated objects, however I don't think that is the correct thing to do here.
use std::collections::HashMap;
struct O {
a: i32,
b: i32,
}
fn main() {
let mut objects = vec![
O { a: 1, b: 0 },
O { a: 2, b: 0 },
O { a: 3, b: 0 },
O { a: 4, b: 1 },
];
let mut b_to_o: HashMap<i32, Vec<&O>> = HashMap::new();
for o in &objects {
b_to_o.entry(o.b).or_insert(Vec::new()).push(&o);
}
let b_zero: &Vec<&O> = b_to_o.get(&0).unwrap();
let b_zero_a_odd: Vec<&O> = b_zero
.iter()
.filter(|o| o.a % 2 == 0)
//.map(|o| *o)
.collect::<Vec<&O>>();
}
NOTE: Vector of objects doesn't have to be mut in this example, but it has to be in the code I am reproducing.
You have a Vec<&T> and iter yields &Output, where Output is the inner type of the Vec, in this case &T, you you get: &Output => &&T.
There is nothing wrong on dereferencing the double reference, you can use map, or you can use filter_map as a single step (notice the pattern mathing in the closure parameter to dereference directly |&o|):
let b_zero_a_odd: Vec<&O> = b_zero
.iter()
.filter_map(|&o| if o.a % 2 == 0 { Some(o) } else { None })
.collect::<Vec<&O>>();
Playground

How to print both the index and value for every element in a Vec?

I'm trying to complete the activity at the bottom of this page, where I need to print the index of each element as well as the value. I'm starting from the code
use std::fmt; // Import the `fmt` module.
// Define a structure named `List` containing a `Vec`.
struct List(Vec<i32>);
impl fmt::Display for List {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Extract the value using tuple indexing
// and create a reference to `vec`.
let vec = &self.0;
write!(f, "[")?;
// Iterate over `vec` in `v` while enumerating the iteration
// count in `count`.
for (count, v) in vec.iter().enumerate() {
// For every element except the first, add a comma.
// Use the ? operator, or try!, to return on errors.
if count != 0 { write!(f, ", ")?; }
write!(f, "{}", v)?;
}
// Close the opened bracket and return a fmt::Result value
write!(f, "]")
}
}
fn main() {
let v = List(vec![1, 2, 3]);
println!("{}", v);
}
I'm brand new to coding and I'm learning Rust by working my way through the Rust docs and Rust by Example. I'm totally stuck on this.
In the book you can see this line:
for (count, v) in vec.iter().enumerate()
If you look at the documentation, you can see a lot of useful functions for Iterator and enumerate's description states:
Creates an iterator which gives the current iteration count as well as the next value.
The iterator returned yields pairs (i, val), where i is the current index of iteration and val is the value returned by the iterator.
enumerate() keeps its count as a usize. If you want to count by a different sized integer, the zip function provides similar functionality.
With this, you have the index of each element in your vector. The simple way to do what you want is to use count:
write!(f, "{}: {}", count, v)?;
This is a simple example to print the index and value of a vector:
fn main() {
let vec1 = vec![1, 2, 3, 4, 5];
println!("length is {}", vec1.len());
for x in 0..vec1.len() {
println!("{} {}", x, vec1[x]);
}
}
This program output is -
length is 5
0 1
1 2
2 3
3 4
4 5

Alternative to Vec::chunks() that consumes the vector

I have the following function, which takes a vector as argument and returns a vector of its pairs of elements:
fn to_pairs(flat: Vec<u64>) -> Vec<(u64, u64)> {
assert!(flat.len() % 2 == 0);
let mut pairs = Vec::new();
pairs.reserve(flat.len() / 2);
for pair in flat.chunks(2) {
assert!(pair.len() == 2);
pairs.push((pair.get(0).unwrap().clone(), pair.get(1).unwrap().clone()));
}
pairs
}
I want consume the vector flat so I don't have to clone its elements when constructing the pair.
Is it possible to do so without reimplementing a variation of Vec::chunks() myself?
I want consume the vector flat so I don't have to clone its elements when constructing the pair.
Convert the input Vec into an iterator, then take two things from the iterator at a time. Essentially, you want the same thing as processing a Range (an iterator) in chunks:
fn to_pairs<T>(flat: Vec<T>) -> Vec<(T, T)> {
let len = flat.len();
assert!(len % 2 == 0);
let mut pairs = Vec::with_capacity(len / 2);
let mut input = flat.into_iter().peekable();
while input.peek().is_some() {
match (input.next(), input.next()) {
(Some(a), Some(b)) => pairs.push((a, b)),
_ => unreachable!("Cannot have an odd number of values"),
}
}
pairs
}
fn main() {
assert_eq!(vec![(1,2), (3,4)], to_pairs(vec![1,2,3,4]));
assert_eq!(vec![(true,true), (false,false)], to_pairs(vec![true,true,false,false]));
}
The assert!(len % 2 == 0); is quite important here, as Iterator makes no guarantees about what happens after the first time next returns None. Since we call next twice without checking the first value, we could be triggering that case. In other cases, you'd want to use fuse.
As pointed out by Kha, you could simplify the while loop a bit:
let mut input = flat.into_iter();
while let (Some(a), Some(b)) = (input.next(), input.next()) {
pairs.push((a, b));
}

Write a recursive function that returns a stack of Fibonacci sequence

My teacher just asked this question in the exam and I have no idea where to go on.
More details, the prototype of function is given as:
stack<int> Fibonacci_sequence(int n); //fibonacci numbers count up to n
The point is this function is recursive and it should return a stack data type. In my opinion I don't think this is a possible thing to do, but my teacher asked it!!
P.s: sorry, my language is C++
function stack<int> Fibonacci_sequence(int n) {
if n == 0 {
var a stack<int>;
a.push(0);
return a
} else if n == 1 {
var a stack<int>;
a.push(0);
a.push(1);
return a
} else
var temp int;
var seq int;
seq = Fibonacci_sequence(n-1);
temp = seq.pop;
seq.push(temp);
seq.push(temp);
//above: the top element of the stack must be duplicated because it
//is popped off in the process of calculating the sum.
seq.push(seq.pop()+Fibonacci_sequence(n-2).pop());
return seq
}
}
Above is a function that does just that, written in pseudo code because you did not specify a language. Hopefully this helps, it was fun to come up with! Thanks for the interesting question.
Since you didn't specify a language, and you specified it's an exam, here it is in Ruby. Ruby provides stack operations for arrays, but I'm only using push and pop operations in the following so you should be able to easily translate it to the language of your choice.
def fib(n) # no explicit return type, since everything's an object in Ruby
fail "negative argument not allowed" if n < 0
if n > 1
stack = fib(n - 1)
# grab the last two values...
f_n_1 = stack.pop
f_n_2 = stack.pop
# ...and use them to calculate the next.
# The value of this expression is the resulting stack, return it
return stack.push(f_n_2).push(f_n_1).push(f_n_1 + f_n_2)
elsif n == 1
return fib(0).push(1)
else
return [].push(0)
end
end
p fib(10) # => [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
You may have to translate this to the language of your exam, but that's appropriate.
Here is my C++ code based on #Elliot pseudo, and it got errors, I specified these errors in the code. And I just figure out that pop() doesn't return a value, I'm gonna fix this.
stack<int> Fibonacci_sequence(int n)
{
if (n == 0) {
stack<int> a;
a.push(0);
return a;
}
else if (n == 1) {
stack<int> a;
a.push(0);
a.push(1);
return a;
}
else
{
int temp;
temp = Fibonacci_sequence(n - 1).pop(); //error C2440: '=': cannot convert from 'void' to 'int'
Fibonacci_sequence(n - 1).push(temp);
Fibonacci_sequence(n - 1).push(temp);
//above: the top element of the stack must be duplicated because it
//is popped off in the process of calculating the sum.
return Fibonacci_sequence(n - 1).push(Fibonacci_sequence(n - 1).pop() + Fibonacci_sequence(n - 2).pop());//error C2186: '+': illegal operand of type 'void'
}
}

Resources