Búsqueda en Rust: encontramos el índice de un elemento del array con el máximo rendimiento

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: ¿Por qué buscar un índice en Rust no es simplemente "encontrar y devolver"?

\n\n

Cada desarrollador que migra a Rust desde Python o JavaScript, tarde o temprano se pregunta: "¿Cómo encuentro aquí el índice de un elemento en un array o vector?" En Python se hace con una línea list.index(element), en JavaScript con array.indexOf(element). Pero Rust, como un verdadero perfeccionista, ofrece no una, sino varias formas, cada una con sus propios matices de rendimiento y seguridad.

\n\n

Analicemos cómo encontrar el índice de un elemento en las colecciones de Rust (arrays, vectores y slices) de manera que el código no solo sea correcto, sino también rápido. ¡Porque en la programación de sistemas, cada nanosegundo cuenta!

\n\n

Conceptos básicos: métodos principales para buscar un índice en Rust

\n\n

En la biblioteca estándar de Rust hay dos "jugadores" principales para buscar un índice: position() y rposition(). Están disponibles para cualquier iterador, y por lo tanto también para arrays, vectores y slices.

\n\n

Método position(): búsqueda de izquierda a derecha

\n\n

position() toma un closure y devuelve un Option<usize> — el índice del primer elemento que cumple la condición, o None si no se encuentra dicho elemento.

\n\n
fn main() {\n    let numbers = vec![10, 20, 30, 40, 50];\n    \n    // Buscamos la primera aparición del número 30\n    let index = numbers.iter().position(|&x| x == 30);\n    \n    match index {\n        Some(i) => println!("Índice del número 30: {}", i), // Salida: 2\n        None => println!("Elemento no encontrado"),\n    }\n}\n
\n\n

Tenga en cuenta: llamamos a iter() antes de position(). Esto es importante, ya que position() es un método del trait Iterator, no de la colección en sí.

\n\n

Método rposition(): búsqueda de derecha a izquierda

\n\n

Si necesita el último índice de aparición de un elemento, use rposition(). Funciona de manera similar, pero recorre la colección desde el final:

\n\n
fn main() {\n    let data = vec!['a', 'b', 'c', 'b', 'a'];\n    \n    // Encontremos la última aparición de 'b'\n    let last_b = data.iter().rposition(|&c| c == 'b');\n    \n    println!("Última 'b' en el índice: {:?}", last_b); // Some(3)\n}\n
\n\n

Una limitación importante: rposition() solo funciona con colecciones que admiten el recorrido bidireccional (trait DoubleEndedIterator). Afortunadamente, todas las colecciones estándar de Rust cumplen con este requisito.

\n\n

Comparación de rendimiento: position() vs bucle manual

\n\n

Muchos principiantes escriben bucles manualmente, pensando que es más rápido. Verifiquemos esta suposición en la práctica.

\n\n

Consideremos dos enfoques para buscar el índice de un elemento en un vector de 1 millón de números enteros:

\n\n
use std::time::Instant;\n\nfn main() {\n    let large_vec: Vec<i32> = (0..1_000_000).collect();\n    let target = 999_999;\n    \n    // Método 1: position()\n    let start = Instant::now();\n    let pos1 = large_vec.iter().position(|&x| x == target);\n    let duration1 = start.elapsed();\n    println!("position(): {:?}, tiempo: {:?}", pos1, duration1);\n    \n    // Método 2: bucle manual\n    let start = Instant::now();\n    let mut pos2 = None;\n    for (i, &val) in large_vec.iter().enumerate() {\n        if val == target {\n            pos2 = Some(i);\n            break;\n        }\n    }\n    let duration2 = start.elapsed();\n    println!("Bucle manual: {:?}, tiempo: {:?}", pos2, duration2);\n}\n
\n\n

Los resultados en procesadores modernos generalmente muestran que position() funciona tan rápido como el bucle manual, y a veces incluso más rápido gracias a las optimizaciones internas del compilador de Rust (LLVM). Conclusión: use position() — es idiomático, seguro y no es inferior en velocidad.

\n\n

Búsqueda binaria: cuando los datos están ordenados

\n\n

Si su colección está ordenada, debe usar binary_se

Blogs

Book Recommendations