I understand the error, but still have no idea how to cast i to u32/integer.
let n = 2;
for i in [1..10].into_iter() {
if n % i == 0 {
...
}
}
if n % (i as u32) == 0 doesn't work
help: the trait std::ops::Rem<&std::ops::Range<{integer}>> is not implemented for {integer}
In your code, [1..10] is actually a fixed-size array with a range 1..10 as its only element. You want to iterate over range itself rather than that 1-element array:
let n = 2;
for i in 1..10 {
if n % i == 0 {
...
}
}
Related
I need to detect and list string characters of slice that repeat themselves in order more or equal than N times. I managed to write non-higher-order-function solution in Rust already (below), but I wonder if this can be simplified to chaining iter methods.
The idea:
let v = "1122253225";
let n = 2;
Output:
There are 2 repetition of '1'
There are 3 repetition of '2'
There are 2 repetition of '2'
Indexes where repetition happens are not important. Repetition must happen in order (ie. 3 repetition of '2' separated by other values from the other 2 repetition of '2' counts as separate output lines).
My non-iterator solution:
let mut cur_ch = '\0';
let mut repeat = 0;
for ch in v.chars() {
if ch == cur_ch {
repeat = repeat + 1;
}
else {
if repeat >= n {
printf!("There are {} repetition of '{}'", repeat, cur_ch);
}
cur_ch = ch;
repeat = 1;
}
}
if repeat >= n {
printf!("There are {} repetition of '{}'", repeat, cur_ch);
}
It works, but is there a better way to do so with chaining iter methods?
Here is a solution that uses scan and filter_map:
fn main() {
let s = "112225322555";
let n = 2;
let i = s
.chars()
.map(|v| Some(v))
.chain(std::iter::once(None))
.scan((0, None), |(count, ch), v| match ch {
Some(c) if *c == v => {
*count += 1;
Some((None, *count))
}
_ => Some((ch.replace(v), std::mem::replace(count, 1))),
})
.filter_map(|(ch, count)| match ch {
Some(Some(ch)) if count >= n => Some((ch, count)),
_ => None,
});
for (ch, num) in i {
println!("There are {} repititions of {}", num, ch);
}
}
Playground Link
The first step is to use scan to count the number of adjacent characters. The first argument to scan is a state variable, which gets passed to each call of the closure that you pass as the second argument. In this case the state variable is a tuple containing the current character and the number of times it has been seen.
Note:
We need to extend the iteration one beyond the end of the string we are analyzing (otherwise we would miss the case where the end of the string contained a run of characters meeting the criteria). We do this by mapping the iteration into Option<char> and then chaining on a single None. This is better than special-casing a character such as \0, so that we could even count \0 characters.
For the same reason, we use Option<char> as the current character within the state tuple.
The return value of scan is an iterator over (Option<Option<char>>, i32). The first value in the tuple will be None for each repeated character in the iterator, whereas at each boundary where the character changes it will be Some(Some(char))
We use replace to both return the current character and count, at the same time as setting the state tuple to new values
The last step is to use filter_map to:
remove the (None, i32) variants, which indicate no change in the incoming character
filter out the cases where the count does not reach the limit n.
Here's one attempt at using filter_map():
fn foo(v: &str, n: usize) -> impl Iterator<Item = (usize, char)> + '_ {
let mut cur_ch = '\0';
let mut repeat = 0;
v.chars().chain(std::iter::once('\0')).filter_map(move |ch| {
if ch == cur_ch {
repeat += 1;
return None;
}
let val = if repeat >= n {
Some((repeat, cur_ch))
} else {
None
};
cur_ch = ch;
repeat = 1;
val
})
}
fn main() {
for (repeat, ch) in foo("1122253225", 2) {
println!("There are {} repetition of '{}'", repeat, ch);
}
}
And then you can generalize this to something like this:
fn foo<'i, I, T>(v: I, n: usize) -> impl Iterator<Item = (usize, T)> + 'i
where
I: Iterator<Item = T> + 'i,
T: Clone + Default + PartialEq + 'i,
{
let mut cur = T::default();
let mut repeat = 0;
v.chain(std::iter::once(T::default()))
.filter_map(move |i| {
if i == cur {
repeat += 1;
return None;
}
let val = if repeat >= n {
Some((repeat, cur.clone()))
} else {
None
};
cur = i;
repeat = 1;
val
})
}
This would be higher-order, but not sure if it's actually much simpler than just using a for loop!
let vec = iter::repeat("don't satisfy condition 1") // iterator such as next() always "don't " satisfy condition 1"
.take_while(|_| {
satisfycondition1.satisfy() // true is condition 1 is satisfied else false
})
.collect();
This code creates a vector of n elements with n equal to the number of times condition 1 is not respected.
I would like now to create a vector of n + m elements with n equal to the number of times that condition 1 is not respected and m the number of times that condition 2 is not respected.
The code should look like something like this:
let vec = iter::repeat("dont't satisfy condition 1")
.take_while(|_| {
satisfycondition1.satisfy()
})
.union(
iter::repeat("has satisfed condition 1 but not 2 yet")
.take_while(|_| {
satisfycondition2.satisfy()
})
)
.collect();
I know I could create two vectors and then concatenate them but it's less efficient.
You can use this code to understand what does repeat:
use std::iter;
fn main() {
let mut c = 0;
let z: Vec<_> = iter::repeat("dont't satisfy condition 1")
.take_while(|_| {
c = c + 1;
let rep = if c < 5 { true } else { false };
rep
})
.collect();
println!("------{:?}", z);
}
It seems like std::iter::chain is what you're looking for.
use std::iter;
fn main() {
let mut c = 0;
let mut d = 5;
let z: Vec<_> = iter::repeat("don't satisfy condition 1")
.take_while(|_| {
c = c + 1;
let rep = if c < 5 { true } else { false };
rep
// this block can be simplified to
// c += 1;
// c < 5
// Clippy warns about this
})
.chain(
iter::repeat("satisfy condition 1 but not 2").take_while(|_| {
d -= 1;
d > 2
}),
)
.collect();
println!("------{:?}", z);
}
(playground link)
I can't comment on the semantics of your code, though. If you're trying to see which elements of an iterator "satisfy condition 1 but not 2", this wouldn't be how you do it. You would use std::iter::filter twice (once with condition 1 and once with not condition 2) to achieve that.
In Clojure, I use a function called iterate that:
Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects
Is there something similar in Rust?
For example, I have this function that I'd like to pass to a function with a number and then iterate over a stream/range/vector until I find Some(1):
fn coltz(n: u64) -> Option<u64> {
match n % 2 {
0 => Some(n / 2),
_ => Some(3 * n + 1)
}
}
You can repeatedly call a closure using std::iter::repeat_with():
repeat_with(move || {
let result = x;
x = f(x);
result
})
The return value is an iterator over the successive return values of the closure.
We use move to move x into the closure, as the current state of our iteration. Inside the closure we update x with f(x) and return the old value (so in the first iteration we return the original x).
Here is a complete working example:
use std::iter::repeat_with;
fn collatz(n: u64) -> u64 {
match n % 2 {
0 => n / 2,
_ => 3 * n + 1,
}
}
fn iterate<F, X>(f: F, mut x: X) -> impl Iterator<Item = X>
where
F: Fn(X) -> X,
X: Copy,
{
repeat_with(move || {
let result = x;
x = f(x);
result
})
}
fn main() {
for i in iterate(collatz, 12).take_while(|&x| x != 1) {
println!("{}", i);
}
}
Playground
As of Rust 1.34, you can use iter::successors:
fn coltz(n: u64) -> Option<u64> {
match n % 2 {
0 => Some(n / 2),
_ => Some(3 * n + 1),
}
}
use std::iter;
fn main() {
let sequence = iter::successors(Some(10), |&v| coltz(v)).take_while(|&v| v != 1);
for v in sequence {
println!("{}", v);
}
}
12
6
3
10
5
16
8
4
2
When using below function:
fn factors(number: &BigInt) -> Vec<BigInt> {
let mut n = number.clone();
let mut i: BigInt = ToBigInt::to_bigint(&2).unwrap();
let mut factors = Vec::<BigInt>::new();
while i * i <= n {
if (n % i) == ToBigInt::to_bigint(&1).unwrap() {
i = i + ToBigInt::to_bigint(&1).unwrap();
}
else {
n = n/i as BigInt;
factors.push(i);
}
i = i + ToBigInt::to_bigint(&1).unwrap();
}
if n > i {
factors.push(n);
}
factors
}
I get moved value errors for literally every time i or n is used, starting from the line with while, also in the if. I have read about borrowing, which I understand decently, but this thing I don't understand.
I am not "copying" the value at all, so I don't see anywhere were I could lose ownership of the variables.
Mul (and the other arithmetic operators) take the parameters by value, so i * i move the value i (this is not a problem for primitive numbers because they implement Copy - BigInt does not).
As Mul is implemented for (two) &BigInt, you can do the multiplication (and the other arithmetic operations) with &:
use num::*;
fn factors(number: &BigInt) -> Vec<BigInt> {
let mut n = number.clone();
let mut i = BigInt::from(2);
let mut factors = Vec::new();
while &i * &i <= n {
if (&n % &i) == BigInt::one() {
i = i + BigInt::one();
} else {
n = n / &i;
factors.push(i.clone());
}
i = i + BigInt::one();
}
if n > i {
factors.push(n);
}
factors
}
Note that I also made some simplifications, like omitting the type on Vec::new and using BigInt::from (cannot fail).
Remember that operators in Rust are just syntactic sugar for function calls.
a + b translates to a.add(b).
Primitive types such as i32 implement the trait Copy. Thus, they can be copied into such an add function and do not need to be moved.
I assume the BigInt type you are working with does not implement this trait.
Therefore, in every binary operation you are moving the values.
I've been trying to rewrite the code below for summing floating point numbers while minimizing the rounding errors, but I found it pretty hard to do in Rust. Any suggestions would be greatly appreciated. I attach my non-working Rust attempt
def msum(iterable):
"Full precision summation using multiple floats for intermediate values"
# Rounded x+y stored in hi with the round-off stored in lo. Together
# hi+lo are exactly equal to x+y. The inner loop applies hi/lo summation
# to each partial so that the list of partial sums remains exact.
# Depends on IEEE-754 arithmetic guarantees. See proof of correctness at:
#www-2.cs.cmu.edu/afs/cs/project/quake/public/papers/robust-arithmetic.ps
partials = [] # sorted, non-overlapping partial sums
for x in iterable:
i = 0
for y in partials:
if abs(x) < abs(y):
x, y = y, x
hi = x + y
lo = y - (hi - x)
if lo:
partials[i] = lo
i += 1
x = hi
partials[i:] = [x]
return sum(partials, 0.0)
The code below is what I have in Rust so far, but it's not working yet
fn inexact_sum(v: &Vec<f64>) -> f64 {
let mut partials: Vec<f64> = vec![];
for x in v {
let mut i: usize = 0;
let mut hi: f64;
let mut lo: f64;
for y in partials.clone().iter() {
hi = x + y;
lo = if x.abs() < y.abs() {
y - (hi - x)
} else {
x - (hi - y)
};
if lo != 0.0_f64 {
partials[i] = lo;
i += 1;
}
let x = hi;
println!("x = {}, y = {}", x, y);
}
partials.truncate(i);
partials.push(hi);
}
partials.iter().fold(0.0_f64, |a, b| a + b)
}
EDIT: Thinking about it a bit more, indeed, the error the compiler gave me error: use of possibly uninitialized variable: `hi` is indeed useful. I should have paid more attention to it. The point is that the first time the loop does not execute at all, so hi does not get initialized. So if I change partials.push(hi); to partials.push(*x); the code compiles and runs but it does not give the right answer.
Is this what you are looking for? I think you did not mean to clone the partials array but found that you needed to in order to satisfy the borrow checker; if you try to use the code:
for y in partials.iter() {
...
partials[i] = lo;
The borrow checker will complain:
<anon>:13:17: 13:25 error: cannot borrow `partials` as mutable because it is also borrowed as immutable [E0502]
I got around this by using an index into the array instead:
for j in 0..partials.len() {
let mut y = partials[j];
Then you are not cloning the whole array of partials each time around the outer loop! Since the partials array can be modified whilst iterating through it, taking a clone first means you will end up with the old value of y instead of the new one if it has been modified.
use std::mem;
fn msum(v: &[f64]) -> f64 {
let mut partials: Vec<f64> = vec![];
for x in v {
let mut x = *x;
let mut i = 0;
for j in 0..partials.len() {
let mut y = partials[j];
if x.abs() < y.abs() { mem::swap(&mut x, &mut y) }
let hi = x + y;
let lo = y - (hi - x);
if lo != 0.0 {
partials[i] = lo;
i += 1;
}
x = hi;
}
partials.truncate(i);
partials.push(x);
}
partials.iter().fold(0., |a, b| a + b)
}
fn main() {
let v = vec![1.234, 1e16, 1.234, -1e16];
println!("{}",msum(&v));
}
Playpen