mh8
mh8

Reputation: 33

Fill a vector of struct elements by iteration rather than using .push() one by one

I am trying to find an elegant way to fill a vector of struct elements with a loop or logic instead of writing one .push() for every element I create.

The struct element is a question with many more fields than in the following example and the instances need to be mutable because they are modified by user input :

struct Question {
    id: usize,
    question: String,
}

fn main() {
    //A large and growing list of questions
    let mut q0 = Question {
        id: 0,
        question: String::from("A field I fill in manually"),
    };
    //  .
    //  .
    //  .
    let mut q100 = Question {
        id: 100,
        question: String::from("Another field, each one is different"),
    };

    let total_questions: usize = 100;

    let mut w: Vec<String> = Vec::new();
    for a in 0..total_questions {
        let s = format!("q{}", a);
        w.push(s);
    }
    //w contains ["q0", "q1", ..., "q100"] but is of type std::string::String

    let mut v: Vec<&mut Question> = Vec::new();
    //Expects type struct `main::Question`

    //I would like to avoid :
    v.push(&mut q0);
    v.push(&mut q1);
    //  .
    //  .
    //  .
    v.push(&mut q100);
}

I am not sure that in my example the w: Vec<String> is of any use.

I have looked into .collect() but could not understand how to utilize it in my case.

I'd be happy to be pointed towards a similar question if this is a duplicate I have not found one.

Edit : I have changed the structs string content as it was misleading. They each contain Strings that are unique and cannot be generated. I also realized that Stack Overflow automatically included this in a some_fn() function when we are actually inside main()

Upvotes: 2

Views: 4880

Answers (2)

trent
trent

Reputation: 28005

The problem is because you don't have any data structure that contains the Questions -- you just have 100+ independent local variables -- it's not possible to iterate over them to fill the Vec. You can fix this by putting all the Questions in a Vec<Question> as you create them. Here's an example:

let mut v: Vec<Question> = vec![
    Question {
        id: 0,
        question: String::from("Q0"),
    },
    // ...
    Question {
        id: 100,
        question: String::from("Q100"),
    },
];

In fact, once you do this you probably don't need the Vec<&mut Question> at all, since you can mutate the questions directly by indexing v. However, if you do need the vector of references for some reason, you can create it by collecting an iterator:

let v_refs: Vec<&mut Question> = v.iter_mut().collect();

Upvotes: 3

Jens
Jens

Reputation: 9416

If you can generate your Question object with a function you can use an iterator. Here is an example which just generates numbered Question objects out of a numeric range:

struct Question {
    id: usize,
    question: String,
}

fn main() {
    let v: Vec<Question> = (0..10)
        .map(|x| Question {
            id: x,
            question: "Q".to_string() + &x.to_string(),
        })
        .collect();

    for x in &v {
        println!("{}: {}", x.id, x.question);
    }
}

Here is an example where you get the strings from an array of strings:

struct Question<'a> {
    id: usize,
    question: &'a str,
}

const QUESTIONS: [&str; 3] = ["A", "B", "C"];

fn main() {
    let v: Vec<Question> = (0..questions.len())
        .map(|x| Question {
            id: x,
            question: questions[x],
        })
        .collect();

    for x in &v {
        println!("{}: {}", x.id, x.question);
    }
}

Upvotes: 0

Related Questions