5
\$\begingroup\$

I'm new to Rust and trying to convert some Python to Rust. I have the following in Python:

>>> v = ((0, 0), (1,1), (2, 2))
>>> strings = "\n".join(("%s: (%s, %s)" % (i, val[0], val[1]) for i,val in enumerate(v))))
>>> print(strings)
0: (0, 0)
1: (1, 1)
2: (2, 2)

I'm trying to find the best/smartest/most rustic way of doing this:

let v = vec![(0, 0), (1,1), (2, 2)];

let strings = v
    .iter()
    .enumerate()
    .map(|(i, &(a,b))| format!("{:?}: ({}, {})", i, a, b))
    .collect::<Vec<_>>()
    .join("\n");

println!("{}", strings);
\$\endgroup\$
2
\$\begingroup\$

Your code is reasonable, but there some small tweaks you could do.

  1. Check out itertools, which adds some nice extensions to iterators. Specifically, it allows joining an iterator, instead of needing to collect to an intermediate Vec.

  2. I'm unclear why you would use the Debug formatter for an integer.

  3. Tuples have a space after the comma, between elements (see in the closure).

  4. Your example might just be overly minimized, but there's no reason to use a Vec here, an array would suffice.

extern crate itertools;

use itertools::Itertools;

fn main() {
    let v = [(0, 0), (1, 1), (2, 2)];

    let strings = v.iter()
        .enumerate()
        .map(|(i, &(a, b))| format!("{}: ({}, {})", i, a, b))
        .join("\n");

    println!("{}", strings);
}

If you are OK changing the semantics a little, you can move the newline into the format! and collect into a String:

fn main() {
    let v = [(0, 0), (1, 1), (2, 2)];

    let strings: String = v.iter()
        .enumerate()
        .map(|(i, &(a, b))| format!("{}: ({}, {})\n", i, a, b))
        .collect();

    println!("{}", strings);
}

Note that there is now a trailing newline on the string.

The "unfortunate" thing about these solutions is that they all require intermediate string allocations - the result of format!.

There's a less-common method in itertools to deal with this: format_with:

extern crate itertools;

use itertools::Itertools;

fn main() {
    let v = [(0, 0), (1, 1), (2, 2)];

    let formatter = v.iter()
        .enumerate()
        .format_with("\n", |(i, &(a, b)), fmt| {
            fmt(&format_args!("{}: ({}, {})", i, a, b))
        });

    let strings = format!("{}", formatter);

    println!("{}", strings);
}

I wouldn't worry about this until you know you need that extra bit of performance ^_^

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.