Home
Search
Rust Vec Equals Example (Benchmark)Compare the element contents of vectors with equals. Benchmark how fast vectors can be tested.
Vec Equals. A common requirement in Rust involves testing whether 2 Vectors or slices have the same element contents and lengths. This can be done with a for-loop.
vec
for
But slices have the Eq trait, which means they can be compared with equals expressions. This compares the actual elements, and it is optimized for faster testing than a loop.
First example. We create 2 vectors, each with 3 elements. These vectors have the same exact data, but they are not the same vector—they are separate in memory.
Equals The first 2 vectors are considered equal when we test them with the equality operator.
Not equal We create a third vector with different elements. It is not equal (even though it has the same length).
So The equality operator tests the exact element contents. It is the same as a function that tests the length, and each element.
fn main() { let buffer = vec![10, 20, 30]; let mut buffer2 = vec![]; buffer2.push(10); buffer2.push(20); buffer2.push(30); // See if contents of 2 vectors are the same. if buffer == buffer2 { println!("SLICES ARE EQUAL"); } let buffer3 = vec![1000, 2000, 3000]; if buffer != buffer3 { println!("NOT EQUAL"); } }
SLICES ARE EQUAL NOT EQUAL
Capacity example. Can 2 vectors with different capacities be equal? In this program we find that the capacity is ignored—just the element data and count is compared.
Tip The Vec equality operation is robust and works as expected. It tests element count, and element values.
fn main() { // See if capacity affects equality of 2 vectors. let mut vector1 = Vec::with_capacity(6000000); vector1.push(9); let mut vector2 = Vec::with_capacity(10); vector2.push(9); if vector1 == vector2 { println!("VECTORS ARE EQUAL, CAPACITY IGNORED"); } }
VECTORS ARE EQUAL, CAPACITY IGNORED
Benchmark, entire vec. Suppose we want to compare 2 vectors (or slices) in the fastest way possible. Is the equality operator the best choice here?
Version 1 This version of the code tests 2 vectors for equality directly, using the equals signs.
Version 2 We implement a vector-equality loop, which tests the length and each element.
Result It is about 3 times faster to use the equals signs when comparing 2 vectors.
use std::time::*; fn main() { let max = 1000000; let mut count = 0; let mut count2 = 0; // Create 2 Vectors to compare. let mut buffer = vec![]; for _ in 0..max { buffer.push(5); } let mut buffer2 = vec![]; for _ in 0..max { buffer2.push(5); } // Version 1: test with equals. let now = Instant::now(); if buffer == buffer2 { count += 1; } println!("{} ns", now.elapsed().as_nanos()); // Version 2: test with for-loop. let now = Instant::now(); let mut equal = false; if buffer.len() == buffer2.len() { equal = true; for index in 0..buffer.len() { if buffer[index] != buffer2[index] { equal = false; break; } } } if equal { count2 += 1; } println!("{} ns", now.elapsed().as_nanos()); println!("Counts: {}, {}", count, count2); }
274916 ns 797250 ns Counts: 1, 1
Benchmark, looping. Suppose we want to loop over a slice of u8 bytes, and find a specific pattern of bytes in the slice. We could use chained if-checks on individual bytes.
Version 1 We use a slice-based comparison. We take a slice at each index, and compare it to a constant array of data.
Version 2 We test individual bytes with "if" and chain them together with the binary "and" operator.
if
Result Testing slices at each index is faster than using checking individual bytes, but not by much.
Tip Taking slices is fast and can be done in a tight inner loop with no worries.
use std::time::*; fn main() { // The data to test. let mut data = vec![]; for _ in 0..1000000 { data.push(0); data.push(10); data.push(20); data.push(30); } let mut count1 = 0; let mut count2 = 0; // Version 1: use slice-based test. let t0 = Instant::now(); for _ in 0..1000 { for i in 3..data.len() { let slice_here = &data[i - 3..=i]; if slice_here == [0, 10, 20, 30] { count1 += 1; } } } println!("{}", t0.elapsed().as_millis()); // Version 2: Use individual index tests. let t1 = Instant::now(); for _ in 0..1000 { for i in 3..data.len() { if data[i - 3] == 0 && data[i - 2] == 10 && data[i - 1] == 20 && data[i] == 30 { count2 += 1; } } } println!("{}", t1.elapsed().as_millis()); println!("{} {}", count1, count2); }
2550 ms (slice equals) 2834 ms 1000000000 1000000000
Vectors and slices. In Rust we can use Vecs as slices by using a reference. It is usually best to act upon slices as they are more versatile (other things can be slices, not just vectors).
A summary. Comparing 2 slices for equality in Rust compares the individual elements and the lengths. It does not consider capacity, and it is much faster than a for-loop.
Home
© 2007-2022 sam allen.
see site info on the changelog.