2 votes

Comment éviter les boucles for et l'instruction let dans ce programme ?

En Rust, comment éviter d'écrire des boucles for et des instructions let ? Ce programme est utilisé pour enregistrer sur quelle ligne de texte la chaîne apparaît et la position où elle apparaît sur la ligne.

Je sais que je peux utiliser les itérateurs et map pour les éliminer, mais je viens de contacter Rust, je ne sais pas comment l'écrire.

pub struct L{
    x: usize,
    y: usize,
}
pub fn foo (text: &str, string: &str)->Vec<L> {
    let mut r= Vec::new();
    let mut x=0;
    for line in text.lines(){
        for (y, _) in line.match_indices(string){
            r.push(L{
                    x : x,
                    y: y, })
        }
        x+=1;
    }
    r
}

7voto

kmdreko Points 3321

C'est l'équivalent de l'utilisation des itérateurs :

pub fn foo(text: &str, string: &str) -> Vec<L> {
    text.lines()
        .enumerate()
        .flat_map(|(x, line)| {
            line.match_indices(string).map(move |(y, _)| { L { x, y } })
        })
        .collect()
}

Démonté ligne par ligne :

.enumerate()

enumerate est utilisé pour transformer un itérateur de T en un itérateur de (usize, T) ce qui revient à compresser la valeur originale avec l'indice. Vous faites cela parce que vous gardez la trace du numéro de ligne avec la fonction x .

.flat_map(|(x, line)| { ... })

flat_map est utilisé pour permettre à chaque valeur de l'itérateur de retourner son propre itérateur dont les valeurs sont ensuite aplaties en un seul flux.

line.match_indices(string).map(move |(y, _)| { L { x, y } })

Ici, nous utilisons simplement map pour prendre le x et le y et créer un L . move est utilisé car sinon x sera emprunté pour la fermeture, mais l'itérateur et la fermeture sont renvoyés à l'utilisateur. flat_map fermeture, vivant plus longtemps que x . Le site move ne fait que copier le x donc ce n'est pas un problème.

.collect()

collect est utilisé pour convertir un itérateur en quelque chose qui peut être fait à partir de l'itérateur en mettant en œuvre la fonction FromIterator généralement des collections comme Vec . Cette méthode utilise également l'inférence de type en sachant que nous retournons un fichier Vec<L> il sait qu'il faut collecter dans un Vec<L> .


Vous pouvez vérifier l'équivalence sur le Rust Playground .

1voto

Ibraheem Ahmed Points 5030

Voici le code que vous avez fourni converti pour utiliser les itérateurs :

pub fn foo(text: &str, string: &str) -> Vec<L> {
  text
    .lines()
    // Allows us to get the current count *and* the element during iteration
    .enumerate()
    // flatten the inner iterator into one single iterator
    .flat_map(|(index, line)| {
      line
        .match_indices(string)
        // the inner iterator
        .map(move |(y, _)| L { x: index, y: y })
    })
    // collect the iterator into a `Vec` of `L`
    .collect::<Vec<L>>()
}

0voto

Alex Larionov Points 343

On peut essayer comme ça : Terrain de jeux

#[derive(Debug)]
pub struct L {
    x: usize,
    y: usize,
}

pub fn foo (text: &str, string: &str) -> Vec<L> {
    text.lines()
        .enumerate()
        .map(|(x, line)| 
            line.match_indices(string)
                .map(move |(y, _)| L{x, y}))
        .flatten()
        .collect()
}

fn main() {
    println!("{:?}", foo(
            "aaa bbb ccc\nbbb aaa ccc\nccc aaa bbb", 
            "bbb"))
    // [L { x: 0, y: 4 }, L { x: 1, y: 0 }, L { x: 2, y: 8 }]
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X