Reputation: 11259
My original approach:
pub fn find_the_difference(s: String, t: String) -> char {
let mut c:u8 = 0;
for i in 0..s.chars().count() {
c ^= t.chars().nth(i).unwrap() as u8 ^ s.chars().nth(i).unwrap() as u8;
}
return (c ^ t.chars().nth(s.chars().count()).unwrap() as u8) as char;
}
But it was too slow and quite crazy also all what I had to write to replace t[i] ^ s[i]
(see below original C++ function). So I looked for something else and found this method where we convert the string into a char array and got some good results (went from 8ms to 0ms).
pub fn find_the_difference(s1: String, t1: String) -> char {
let mut c:u8 = 0;
let s: Vec<char> = s1.chars().collect();
let t: Vec<char> = t1.chars().collect();
for i in 0..s1.chars().count() {
c ^= t[i] as u8 ^ s[i] as u8;
}
return (c ^ t[s1.chars().count()] as u8) as char;
}
But perhaps no need to collect, nor do I care about index, I just want to iterate on one char after another. My current attempt:
pub fn find_the_difference(s1: String, t1: String) -> char {
let mut c:u8 = 0;
let mut s = s1.chars();
let mut t = t1.chars();
let n = s.count();
for i in 0..n {
c ^= t.next().unwrap() as u8 ^ s.next().unwrap() as u8; // c ^= *t++ ^ *s++ translated in C++
}
return (c ^ t.next().unwrap() as u8) as char;
}
I get the following error message:
Line 9, Char 44: borrow of moved value: `s` (solution.rs)
|
4 | let mut s = s1.chars();
| ----- move occurs because `s` has type `std::str::Chars<'_>`, which does not implement the `Copy` trait
5 | let mut t = t1.chars();
6 | let n = s.count();
| - value moved here
...
9 | c ^= t.next().unwrap() as u8 ^ s.next().unwrap() as u8;
| ^ value borrowed here after move
error: aborting due to previous error
Is it possible to achieve this kind of code c = *t++
?
NB: s1.chars.count() = t1.chars.count() - 1 and the goal is to find the extra letter in t1
NB2: original C++ function:
char findTheDifference(string s, string t) {
char c = 0;
for (int i = 0; t[i]; i++)
c ^= t[i] ^ s[i];
return c;
}
Upvotes: 1
Views: 6582
Reputation: 5325
I think you're confused about the differences between C and Rust string handling, and the distinctions between Rust's str
, String
, &[u8]
, char
, and u8
types.
That said, here is how I'd implement your function:
fn find_the_difference(s: &[u8], t: &[u8]) -> u8 {
assert!(t.len() > s.len());
let mut c: u8 = 0;
for i in 0..s.len() {
c ^= s[i] ^ t[i];
}
c ^ t[s.len()]
}
If your data is currently String
, you can get a &[u8]
view of it using the as_bytes()
method. Like this:
let s: String = ...some string...;
let t: String = ...some string...;
let diff = find_the_difference(s.as_bytes(), t.as_bytes());
Upvotes: 6
Reputation: 165546
zip
the two iterators together.
And, as Peter Hall comments, it's safer. You can't assume characters are 1 byte. Just use !=
.
fn main() {
let a = "☃ Thiñgs";
let b = "☃ Thiñks";
let both = a.chars().zip(b.chars());
for pair in both {
if pair.0 != pair.1 {
println!("Different {} {}", pair.0, pair.1);
}
}
}
This will stop when either iterator is exhausted.
If you want the indicies as well, use char_indicies.
Because they are a key feature of Rust, iterators are a "zero-cost abstraction" meaning Rust will do the optimization for you. Iterators are generally as fast or faster than hand-written loops.
Upvotes: 2