うさぎさんに少しでも追いつきたくて、コードを読んでるけどぜんぜん分からないのでメモ。
csv
これ。
Rust bookにはこんな感じの例が載ってる。
extern crate csv; extern crate rustc_serialize; use std::vec::Vec; use std::path::Path; use std::fs; #[derive(Debug, RustcDecodable)] struct Row { country: String, city: String, population: i32, gdp: f64 } fn main() { let data_path = Path::new("path/to/file.csv"); let file = fs::File::open(data_path).unwrap(); let mut rdr = csv::Reader::from_reader(file); for row in rdr.decode::<Row>() { let row = row.unwrap(); } }
(https://doc.rust-lang.org/book/error-handling.html#writing-the-logic)
ここでは、decode()
にRow
のtype hintをつけることで、あらかじめ自分で定義したRow
を使ってパターンマッチングができる。
impl<R: Read> Reader<R> fn decode<'a, D: Decodable>(&'a mut self) -> DecodedRecords<'a, R, D>
DecodedRecordsにはmap()
とかcollect()
があるので、その辺でうまいことVec<f64>
に変換して、forループをやめたい。
map()
の中で副作用があることをする
追記:コメント欄で指摘をもらったのでcollect()
を書き足しました。
extern crate csv; use std::vec::Vec; fn main() { let mut rdr = csv::Reader::from_string("a,b,c\n1,2,3\n4,5,6").has_headers(true); let mut x: Vec<f64> = vec![]; for row in rdr.decode::<Vec<f64>>() { row.unwrap().iter().map(|&c| x.push(c)).collect::<Vec<_>>(); } println!("{:?}", &x); }
iter()
の代わりにinto_iter()
を使うと、こう。
row.unwrap().into_iter().map(|c| x.push(c));
結果
$ ./target/debug/csv.exe [1, 2, 3, 4, 5, 6]
雑な例
ドキュメントの例をなぞるとこんな感じのはず。とりあえずネストしたままのやつ。
extern crate csv; use std::vec::Vec; fn main() { let mut rdr = csv::Reader::from_string("a,b,c\n1,2,3\n4,5,6").has_headers(true); let x: Vec<Vec<f64>> = rdr.decode().collect::<csv::Result<Vec<Vec<f64>>>>().unwrap(); println!("{:?}", x); }
結果
$ ./target/debug/csv.exe [[1, 2, 3], [4, 5, 6]]
Vec<Vec>をVecにする
fold()
すればいけるかなと思ったんですが、extend()
は元の値を返してくれないので、そんなことはできません。
let x: Vec<Vec<f64>> = rdr.decode().collect::<csv::Result<Vec<Vec<f64>>>>().unwrap(); let x: Vec<f64> = x.into_iter().fold(vec![], |v1, v2| v1.extend(v2.iter().cloned()));
よくわからないのですが、flat_map()
というのを使うといいみたいです。
2回collect()
してるのはなんかいまいちな感じしかしませんけど、これ以上いい書き方が思いつきません。。
extern crate csv; use std::vec::Vec; fn main() { let mut rdr = csv::Reader::from_string("a,b,c\n1,2,3\n4,5,6").has_headers(true); let x: Vec<Vec<f64>> = rdr.decode().collect::<csv::Result<Vec<Vec<f64>>>>().unwrap(); let x: Vec<f64> = x .into_iter() .flat_map(|c| c) .collect(); println!("{:?}", x); }
結果
$ ./target/debug/csv.exe [1, 2, 3, 4, 5, 6]
感想
Rustむずい。何より、ググった時にほとんど役立つ情報が出てこないのがつらい...。