Also you may compare two slices without using zip()
, try it on the Rust Playground:
fn compare<T: Ord>(a: &[T], b: &[T]) -> std::cmp::Ordering {
let mut iter_b = b.iter();
for v in a {
match iter_b.next() {
Some(w) => match v.cmp(w) {
std::cmp::Ordering::Equal => continue,
ord => return ord,
},
None => break,
}
}
return a.len().cmp(&b.len());
}
fn main() {
assert_eq!(std::cmp::Ordering::Equal, compare(&[1, 2, 3], &[1, 2, 3]));
assert_eq!(std::cmp::Ordering::Less, compare(&[1, 0], &[1, 2]));
assert_eq!(std::cmp::Ordering::Less, compare(&[], &[1, 2, 3]));
assert_eq!(std::cmp::Ordering::Greater, compare(&[1, 2, 3], &[1, 2]));
assert_eq!(std::cmp::Ordering::Greater, compare(&[1, 3], &[1, 2]));
}
Code review:
You don't need the &self
argument, since you did not use it: self
parameter is only allowed in associated functions and not semantically valid as a function parameter. note: associated functions are those in impl
or trait
definitions
You need use std::cmp;
otherwise rewrite e.g. this: std::cmp::min(a.len(), b.len());
It is not common to return -2
for compare(&[1, 0], &[1, 2]))
Use min_len -= 1;
instead of min_len = min_len - 1;
You may use: ret = a.len() as i64 - b.len() as i64;
which returns length diff instead of:
if a.len() < b.len() {
ret = -1;
} else if a.len() > b.len() {
ret = 1;
}
- You don't need
else
after break
here:
if *p1 != *p2 {
ret = *p1 as i64 - *p2 as i64;
break;
}
- For simple code you may return instead of break:
fn compare(a: &[u8], b: &[u8]) -> i64 {
let mut p1 = a.as_ptr() as *mut u8;
let mut p2 = b.as_ptr() as *mut u8;
let mut min_len = std::cmp::min(a.len(), b.len());
while min_len > 0 {
unsafe {
if *p1 != *p2 {
return *p1 as i64 - *p2 as i64;
}
p1 = p1.offset(1);
p2 = p2.offset(1);
}
min_len -= 1;
}
return a.len() as i64 - b.len() as i64;
}
- You may simply avoid using
unsafe
like the following code:
fn compare(a: &[u8], b: &[u8]) -> i64 {
let mut p1 = a.iter();
let mut p2 = b.iter();
let mut min_len = std::cmp::min(a.len(), b.len());
while min_len > 0 {
let v = *p1.next().unwrap();
let w = *p2.next().unwrap();
if v != w {
return v as i64 - w as i64;
}
min_len -= 1;
}
return a.len() as i64 - b.len() as i64;
}
- You may use generics for more code reusability:
fn compare<T: Ord>(a: &[T], b: &[T]) -> std::cmp::Ordering {
let mut p1 = a.iter();
let mut p2 = b.iter();
let mut min_len = std::cmp::min(a.len(), b.len());
while min_len > 0 {
let v = p1.next().unwrap();
let w = p2.next().unwrap();
if v != w {
return v.cmp(w);
}
min_len -= 1;
}
return a.len().cmp(&b.len());
}
fn main() {
assert_eq!(std::cmp::Ordering::Equal, compare(&[1, 2, 3], &[1, 2, 3]));
assert_eq!(std::cmp::Ordering::Less, compare(&[1, 0], &[1, 2]));
assert_eq!(std::cmp::Ordering::Less, compare(&[], &[1, 2, 3]));
assert_eq!(std::cmp::Ordering::Greater, compare(&[1, 2, 3], &[1, 2]));
assert_eq!(std::cmp::Ordering::Greater, compare(&[1, 3], &[1, 2]));
}
Vec
s, and only requires a contiguousslice
of memory. \$\endgroup\$