Remove consecutive duplicate elements in-place in Rust - vector

I have the following python function that removes consecutive duplicated numbers in-place (meaning [0, 0, 1, 1, 1, 2, 2, 3] becomes [0, 1, 2, 3]):
def del_consec_dupl(nums: List[int]):
for (idx, n) in enumerate(nums):
while idx < len(nums) - 1 and n == nums[idx + 1]:
del nums[idx]
it needs to be rewritten in Rust while respecting the constraint that it must work in-place without allocating an extra vector/array. When trying to literally translating this:
fn del_consec_dupl(nums: &mut Vec<i32>) {
for (idx, n) in nums.iter().enumerate() {
while idx < nums.len() - 1 && *n == nums[idx + 1] {
nums.remove(idx);
}
}
}
will produce the following errors:
error[E0502]: cannot borrow `*nums` as immutable because it is also borrowed as mutable
--> src/main.rs:4:21
|
3 | for (idx, n) in nums.iter_mut().enumerate() {
| ---------------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
4 | while idx < nums.len() - 1 && *n == nums[idx + 1] {
| ^^^^ immutable borrow occurs here
error[E0502]: cannot borrow `*nums` as immutable because it is also borrowed as mutable
--> src/main.rs:4:45
|
3 | for (idx, n) in nums.iter_mut().enumerate() {
| ---------------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
4 | while idx < nums.len() - 1 && *n == nums[idx + 1] {
| ^^^^ immutable borrow occurs here
error[E0499]: cannot borrow `*nums` as mutable more than once at a time
--> src/main.rs:5:13
|
3 | for (idx, n) in nums.iter_mut().enumerate() {
| ---------------------------
| |
| first mutable borrow occurs here
| first borrow later used here
4 | while idx < nums.len() - 1 && *n == nums[idx + 1] {
5 | nums.remove(idx);
| ^^^^ second mutable borrow occurs here
error: aborting due to 3 previous errors
it seems no matter what I do, I can only solve 2 of 3. It seems the main issue here is trying to refer to the length of the vector while it is being mutated inside the iteration.
Would I need an unsafe block here? or how would you go about solving it?

I would not use remove which moves all the elements after the given index and is inefficient, but just overwrite elements in the same array, dealing with the double-borrow problem by using indexes:
fn del_consec_dupl(nums: &mut Vec<i32>) {
let mut di = 0; // "destination" increment
for si in 1..nums.len() { // increment on the "source"
if nums[si] != nums[si-1] {
di += 1;
nums[di] = nums[si];
}
}
nums.truncate(di+1); // cut off the tail
}
There's no need to use unsafe here.

Rust vectors provide the built-in dedup() method which does exactly what you are asking for, so the easiest way to write your code is nums.dedup();.
For integers, or more generally Copy types, you can also implement the same functionality using the retain() method:
fn retain_uniq<T: Copy + PartialEq>(nums: &mut Vec<T>) {
let mut previous = None;
nums.retain(|&x| Some(x) != std::mem::replace(&mut previous, Some(x)))
}

Related

Rust - How to get last element from Vector [duplicate]

I have this code, but its giving me an error I don't understand:
fn main() {
// --snip--
let mut unit = String::new();
std::io::stdin()
.read_line(&mut unit)
.expect("couldn't read line!");
let unit = unit.trim().to_lowercase();
dbg!(unit);
if unit == "f" {
println!("temperature in Celsius is : {}°c", f_to_c(temp));
} else if unit == "c" {
println!("temperature in Fahrenheit is : {}°f", c_to_f(temp));
} else {
println!("'{unit}' unit not supported!");
}
}
error[E0382]: borrow of moved value: `unit`
--> src/lib.rs:16:8
|
13 | let unit = unit.trim().to_lowercase();
| ---- move occurs because `unit` has type `String`, which does not implement the `Copy` trait
14 | dbg!(unit);
| ---------- value moved here
15 |
16 | if unit == "f" {
| ^^^^ value borrowed here after move
I made unit explicitly type String but that wasn't the cause. How is this error is generated?
The dbg! macro moves it's arguments.
You can use it and not consume the argument by passing only a reference like this:
dbg!(&unit);
instead.

How to modify a HashMap with vector values? [duplicate]

This question already has answers here:
How to lookup from and insert into a HashMap efficiently?
(2 answers)
Is there any way to return a reference to a variable created in a function?
(5 answers)
Closed 4 years ago.
I'm trying to build a HashMap with vectors as values and I have problems with borrowing / lifetimes.
The task is to find the funniest words in a given text as ranked by the funny_score method. I would like to store a list of words for each distinct score in a HashMap.
I have the following code
use std::collections::HashMap;
fn main() {
let text = "";
let mut scores: HashMap<usize, &mut Vec<&str>> = HashMap::new();
for word in text.split(' ') {
let funny_score = funny_score(word);
match scores.get_mut(&funny_score) {
Some(list) => list.push(word),
None => {
let mut list = vec![word];
scores.insert(funny_score, &mut list);
}
}
}
}
fn funny_score(_: &str) -> usize { 0 }
And the compiler says
error[E0597]: `list` does not live long enough
--> src/main.rs:12:49
|
12 | scores.insert(funny_score, &mut list);
| ^^^^ borrowed value does not live long enough
13 | }
| - `list` dropped here while still borrowed
...
16 | }
| - borrowed value needs to live until here
error[E0499]: cannot borrow `scores` as mutable more than once at a time
--> src/main.rs:12:17
|
8 | match scores.get_mut(&funny_score) {
| ------ first mutable borrow occurs here
...
12 | scores.insert(funny_score, &mut list);
| ^^^^^^ second mutable borrow occurs here
13 | }
14 | }
| - first borrow ends here
How can I make this work?

Why does iterating a vector of i32s give references to i32 (&i32)?

The following program tries to grade the marks of a student:
use std::io;
fn main() {
let mut in0 = String::new();
io::stdin().read_line(&mut in0).expect("stdin err");
let n: i32 = in0.trim().parse().expect("parse err");
println!("{}", n);
let mut v: Vec<i32> = Vec::new();
for _ in 0..n {
let mut inp = String::new();
io::stdin().read_line(&mut inp).expect("stdin err");
let num: i32 = inp.trim().parse().unwrap();
v.push(num);
}
let out: Vec<_> = v
.iter()
.map(|x| {
if x < 38 {
x
} else if x % 5 > 3 {
x + x % 5
} else {
x
}
})
.collect();
println!("{:?}", v);
}
While compiling, I get the following error.
error[E0308]: mismatched types
--> src/main.rs:19:20
|
19 | if x < 38 {
| ^^
| |
| expected `&i32`, found integer
| help: consider borrowing here: `&38`
error[E0308]: `if` and `else` have incompatible types
--> src/main.rs:24:17
|
21 | } else if x % 5 > 3 {
| ____________________-
22 | | x + x % 5
| | --------- expected because of this
23 | | } else {
24 | | x
| | ^ expected `i32`, found `&i32`
25 | | }
| |_____________- `if` and `else` have incompatible types
|
help: consider dereferencing the borrow
|
23 | } else *{
24 | x
25 | }
How is the x variable a &i32 type and not a i32 type?
Calling the .iter() method on a vector returns an iterator over references the vector's elements. Otherwise, it would have to move or copy the elements out of the vector, which is not desirable in the general case [1]. In the documentation this is not immediately obvious from the declaration:
pub fn iter(&self) -> Iter<T> // Return type does not look like a reference
However, the examples show that you get a reference:
assert_eq!(iterator.next(), Some(&1)); // note the `&1` instead of just `1`
The closure can be instructed to dereference the parameter:
v.iter().map(|&x| { /* do something */ })
This is fine if the vector contains Copyable types like i32. Otherwise this would result in a cannot move out of borrowed content error. In this case you will likely want to work with a reference anyway.
If you no longer need the vector after iterating you can use .into_iter(), which consumes the vector and iterates over owned items instead of references.
[1] Moving would clear the vector, which is covered by the .drain() method, and copying is not possible/efficient on all types.
If you want to consume the Vec, you must use into_iter() method:
use std::io;
fn main() {
let mut in0 = String::new();
io::stdin().read_line(&mut in0).expect("stdin err");
let n: i32 = in0.trim().parse().expect("parse err");
println!("{}", n);
let mut v: Vec<i32> = Vec::new();
for _ in 0 .. n {
let mut inp = String::new();
io::stdin().read_line(&mut inp).expect("stdin err");
let num: i32 = inp.trim().parse().unwrap();
v.push(num);
}
let out: Vec<_> = v.into_iter().map(|x| {
if x < 38 {
x
} else if x % 5 > 3 {
x + x % 5
} else {
x
}
}).collect();
println!("{:?}", out);
}
If you do not consume the vector, the things inside it can only be borrowed, not moved.

Vector of strings reports the error "str does not have a constant size known at compile time"

When trying to print out the contents of a multidimensional vector in Rust, it seems as though you cannot use the type Vec<Vec<str>> for the vector.
fn print_multidimensional_array(multi: &Vec<Vec<str>>) {
for y in 0..multi.len() {
for x in 0..multi[y].len() {
print!("{} ", multi[y][x]);
}
println!("");
}
}
With this code, I get the output:
error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
--> src/main.rs:1:1
|
1 | / fn print_multidimensional_array(multi: &Vec<Vec<str>>) {
2 | | for y in 0..multi.len() {
3 | | for x in 0..multi[y].len() {
4 | | print!("{} ", multi[y][x]);
... |
7 | | }
8 | | }
| |_^ `str` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `str`
= note: required by `std::vec::Vec`
What type of vector could I use for this to work?
Use Vec<Vec<&str>>.
fn print_multidimensional_array(multi: &[Vec<&str>]) {
for y in multi {
for v in y {
print!("{} ", v);
}
println!();
}
}
fn main() {
let v = vec![vec!["a", "b"], vec!["c", "d"]];
print_multidimensional_array(&v);
}
See also:
What does “`str` does not have a constant size known at compile-time” mean, and what's the simplest way to fix it?
What does "Sized is not implemented" mean?
Why is it discouraged to accept a reference to a String (&String), Vec (&Vec), or Box (&Box) as a function argument?
Passing Vec<String> as IntoIterator<&'a str>
What are the differences between Rust's `String` and `str`?
Because I like to make things overly generic...
fn print_multidimensional_array<I>(multi: I)
where
I: IntoIterator,
I::Item: IntoIterator,
<I::Item as IntoIterator>::Item: AsRef<str>,
{
for y in multi {
for v in y {
print!("{} ", v.as_ref());
}
println!();
}
}
fn main() {
let v1 = vec![vec!["a", "b"], vec!["c", "d"]];
let v2 = vec![["a", "b"], ["c", "d"]];
let v3 = [vec!["a", "b"], vec!["c", "d"]];
let v4 = [["a", "b"], ["c", "d"]];
print_multidimensional_array(&v1);
print_multidimensional_array(&v2);
print_multidimensional_array(&v3);
print_multidimensional_array(&v4);
}

F# : Writing a function that builds a list of tuples recursively and change a mutable variable

This question is related to this previous thread.
I followed Tomas's suggestion using this piece code, and all works fine:
let GetSameColorNeighs (grid:Option<Ball>[,], row, col, color:Color) =
let rec loop (row, col) = seq {
if not (row < 0 || col < 0 || row > MaxLineNumber - 1
|| col > BallsPerLine - 1) then
let ball = grid.[row,col]
match ball with
| Some(ball) ->
if (!ball.visited = false || not <| ball.color.Equals(color)) then
// Not sure what you want here - yield items using 'yield'?
// [row , col]
else
ball.visited := true
yield row, col // Add single item to results
yield! loop(row + 1, col + 1) // Add all generated to results
yield! loop(row - 1, col - 1) // -- || --
| None -> () }
loop(row, col) |> Seq.toList
The code above iterate through an array 2d of "balls" and return a list of index of adjacent balls with the same color.
Now I have to modify the function in way that it returns also a boolean indicating if at least one ball of the list satisfy a certain condition. I changed the code this way but seems that I can't assign a mutable value inside that code:
let GetSameColorNeighs (grid:Option<Ball>[,], row, col, color:Color) : List<int * int> * bool =
let mutable b : bool = false
let rec loop (row, col) = seq {
if not (row < 0 || col < 0 || row > MaxLineNumber - 1
|| col > BallsPerLine - 1) then
let ball = grid.[row,col]
match ball with
| Some(ball) ->
if (ball.visited = true || not <| ball.color.Equals(color)) then
()
else
//HERE's THE PROBLEM
if (ball_satisfy_a_certain_condition) then
b <- true
ball.visited := true
yield row, col // Add single item to results
yield! loop(row + 1, col + 1) // Add all generated to results
yield! loop(row - 1, col - 1) // -- || --
| None -> () }
loop(row, col) |> Seq.toList, b
It seems that a mutable variable can't be acquired by a closure (I don't know what it means).
So I have 2 questions:
why is the above assignment to a mutable variable wrong?
How should I refactor my code to achieve this goal?
In short, you have to use ref variables instead of mutable variables.
While mutable variables are allocated on the stack, ref variables are heap-based. After each time your loop function is invoked, mutable values are wiped out when ref values are still there. Therefore, only ref values are valid to return in GetSameColorNeighs.
This question has been asked many times here. See The mutable variable 'i' is used in an invalid way.? and this blog post for more in-depth discussion.

Resources