Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Rust have an equivalent to Python's dictionary comprehension syntax?

How would one translate the following Python, in which several files are read and their contents are used as values to a dictionary (with filename as key), to Rust?

countries = {region: open("{}.txt".format(region)).read() for region in ["canada", "usa", "mexico"]}

My attempt is shown below, but I was wondering if a one-line, idiomatic solution is possible.

use std::{
    fs::File,
    io::{prelude::*, BufReader},
    path::Path,
    collections::HashMap,
};

macro_rules! map(
    { $($key:expr => $value:expr),+ } => {
        {
            let mut m = HashMap::new();
            $(
                m.insert($key, $value);
            )+
            m
        }
     };
);

fn lines_from_file<P>(filename: P) -> Vec<String>
where
    P: AsRef<Path>,
{
    let file = File::open(filename).expect("no such file");
    let buf = BufReader::new(file);
    buf.lines()
        .map(|l| l.expect("Could not parse line"))
        .collect()
}

fn main() {
    let _countries = map!{ "canada" => lines_from_file("canada.txt"),
                           "usa"    => lines_from_file("usa.txt"),
                           "mexico" => lines_from_file("mexico.txt") };
}
like image 201
Sean Pianka Avatar asked Dec 09 '18 00:12

Sean Pianka


1 Answers

Rust's iterators have map/filter/collect methods which are enough to do anything Python's comprehensions can. You can create a HashMap with collect on an iterator of pairs, but collect can return various types of collections, so you may have to specify the type you want.

For example,

use std::collections::HashMap;

fn main() {
    println!(
        "{:?}",
        (1..5).map(|i| (i + i, i * i)).collect::<HashMap<_, _>>()
    );
}

Is roughly equivalent to the Python

print({i+i: i*i for i in range(1, 5)})

But translated very literally, it's actually closer to

from builtins import dict

def main():
    print("{!r}".format(dict(map(lambda i: (i+i, i*i), range(1, 5)))))

if __name__ == "__main__":
    main()

not that you would ever say it that way in Python.

like image 131
gilch Avatar answered Sep 24 '22 12:09

gilch