Convertir cadena de valor clave par en HashMap en una línea

Tengo una cadena con contenidos como los siguientes:

key1:value1 key2:value2 key3:value3 ...

Quiero terminar con un HashMap<&str, &str> (o equivalente), que mapea las teclas y los valores de la cadena (por ejemplo, una búsqueda precipitada de "key1" debe devolver "valor1").

Actualmente, puedo llenar fácilmente el HashMap con lo siguiente:

let mut hm = HashMap::new();
for item in my_string.split_ascii_whitespace() {
    let splits = item.split(":").collect::>();
    hm.insert(splits[0], splits[1]);
}

Sin embargo, ¿qué pasaría si quisiera hacerlo en una línea (incluso a un costo de legibilidad, para "código golf"-ish fines)? Sé cómo hacer esto con un HashSet, así que imagino que parecería algo similar; tal vez algo así (que en realidad no compila):

let hm: HashMap<&str, &str> = HashMap::from_iter(my_string.split_ascii_whitespace().map(|s| s.split(":").take(2).collect::>()));

He probado diferentes combinaciones de cosas similares a las anteriores, pero no puedo encontrar algo que realmente compila.

Pregunta hecha hace 3 años, 4 meses, 27 días - Por bytebard30f9


3 Respuestas:

  • Mi enfoque hacia la solución de este problema era recordar que Iterator puede ser recogido en un HashMap así que sabiendo que trabajé hacia atrás para tratar de averiguar cómo podía convertir un &str en un Iterator que logré utilizar el String find y split_at métodos:

    use std::collections::HashMap;
    
    fn one_liner(string: &str) -> HashMap<&str, &str> {
        string.split_whitespace().map(|s| s.split_at(s.find(":").unwrap())).map(|(key, val)| (key, &val[1..])).collect()
    }
    
    fn main() {
        dbg!(one_liner("key1:value1 key2:value2 key3:value3"));
    }
    

    parque infantil

    El segundo map llamada era necesario para eliminar el líder : carácter de la cadena de valor.

    Respondida el Dec 19, 2020 a las 18:57 - por syntaxsensei

    Votos positivos: 0 | Votos negativos: 0

  • Puedes lograrlo en una línea usando la función fold de Rust para acumular los elementos en un HashMap. Aquí te dejo un ejemplo de cómo hacerlo:

    rust
    use std::collections::HashMap;
    
    fn main() {
        let my_string = "key1:value1 key2:value2 key3:value3";
    
        let hm: HashMap<&str, &str> = my_string.split_ascii_whitespace()
            .fold(HashMap::new(), |mut acc, item| {
                let splits: Vec<&str> = item.split(":").collect();
                acc.insert(splits[0], splits[1]);
                acc
            });
    
        println!("{:?}", hm);
    }
    

    En este código, estamos utilizando fold para iterar sobre los elementos de my_string.split_ascii_whitespace(), dividir cada elemento por ':' y luego insertar la clave y el valor en el HashMap acumulado. Al final, fold devolverá el HashMap completo.

    Respondida el Dec 20, 2020 a las 18:56 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Puedes utilizar el método split_once de las rebanadas de cadena para dividir una cadena en un par de rebanadas en el primer carácter de coincidencia. Esto te permite dividir cada elemento en el HashMap en una línea:

    
    let hm: HashMap<&str, &str> = my_string
        .split_ascii_whitespace()
        .map(|s| s.split_once(':').unwrap())
        .collect();
    

    Respondida el Dec 20, 2020 a las 19:07 - por Gemini

    Votos positivos: 0 | Votos negativos: 0