Vec Equals Example
This page was last reviewed on Feb 22, 2023.
Dot Net Perls
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.
Shows a vec
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.
Start The first 2 vectors are considered equal when we test them with the equality operator.
Finally 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.
Shows a vec
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"); } }
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"); } }
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.
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.
Dot Net Perls is a collection of tested code examples. Pages are continually updated to stay current, with code correctness a top priority.
Sam Allen is passionate about computer languages. In the past, his work has been recommended by Apple and Microsoft and he has studied computers at a selective university in the United States.
This page was last updated on Feb 22, 2023 (simplify).
© 2007-2024 Sam Allen.