2017-05-10 28 views
-1

パイプで区切られたファイルを読み込み、データを処理し、結果をCSV形式で生成したい。Rustでパイプ区切りファイルを読み込んで処理する方法は?

入力ファイルのデータ

A|1|Pass 
B|2|Fail 
A|3|Fail 
C|6|Pass 
A|8|Pass 
B|10|Fail 
C|25|Pass 
A|12|Fail 
C|26|Pass 
C|26|Fail 

私は、列1、列3に機能してグループを適用し、特定のグループに応じて、カラム2の合計を生成したいんです。

私は機能によってグループを適用するには、レコードを維持する方法のポイントにこだわっている:私はのような結果を期待してい

use std::fs::File; 
use std::io::{BufReader}; 
use std::io::{BufRead}; 
use std::collections::HashMap; 

fn say_hello(id: &str, value: i32, no_change : i32) { 

    if no_change == 101 { 
     let mut data = HashMap::new(); 
    } 
    if value == 0 { 
     if data.contains_key(id) { 
      for (key, value) in &data { 
       if value.is_empty() { 

       } 
      } 
     } else { 
      data.insert(id,""); 
     } 
    } else if value == 2 { 
     if data.contains_key(id) { 
      for (key, value) in &data { 
       if value.is_empty() { 

       } else { 

       } 
      } 
     } else { 
      data.insert(id,""); 
     } 
    } 
} 

fn main() { 

    let f = File::open("sample2.txt").expect("Unable to open file"); 
    let br = BufReader::new(f); 
    let mut no_change = 101; 
    for line in br.lines() { 
     let mut index = 0; 
     for value in line.unwrap().split('|') { 
      say_hello(&value,index,no_change); 
      index = index + 1; 
     } 
    } 
} 

name,result,num 
A,Fail,15 
A,Pass,9 
B,Fail,12 
C,Fail,26 
C,Pass,57 

は、特定のはありますパイプで区切られたファイルを読み込み、上記のようなデータを処理する技術? Pythonのパンダはこの要件を達成しましたが、私はRustでそれをやりたい

+2

CSVクレートを使用しますか? https://docs.rs/csv – BurntSushi5

答えて

2

前述のとおり、csv crateを使用すると、ファイルの解析が大幅に遅れます。次に、便宜的にソートを実行するBTreeMapを使用して各行をグループ化するだけです。 entry APIは、効率的にBTreeMapに挿入するのに役立ちます。

extern crate csv; 
extern crate rustc_serialize; 

use std::fs::File; 
use std::collections::BTreeMap; 

#[derive(Debug, RustcDecodable)] 
struct Record { 
    name: String, 
    value: i32, 
    passed: String, 
} 

fn main() { 
    let file = File::open("input").expect("Couldn't open input"); 
    let mut csv_file = csv::Reader::from_reader(file).delimiter(b'|').has_headers(false); 

    let mut sums = BTreeMap::new(); 
    for record in csv_file.decode() { 
     let record: Record = record.expect("Could not parse input file"); 
     let key = (record.name, record.passed); 
     *sums.entry(key).or_insert(0) += record.value; 
    } 

    println!("name,result,num"); 
    for ((name, passed), sum) in sums { 
     println!("{},{},{}", name, passed, sum); 
    } 
} 

あなたは出力が正確であることに注意しましょう:

name,result,num 
A,Fail,15 
A,Pass,9 
B,Fail,12 
C,Fail,26 
C,Pass,57 
+0

@ Shepmaster-どのようにoutput.csvのような1つのcsvファイルでこの結果をプッシュできますか? – kit

+0

@ Shepmaster-はい。とった。ご協力いただきありがとうございます。 – kit

1

私はこのような何かをお勧めしたい:ここ

use std::str; 
use std::collections::HashMap; 
use std::io::{BufReader, BufRead, Cursor}; 

fn main() { 
    let data = " 
A|1|Pass 
B|2|Fail 
A|3|Fail 
C|6|Pass 
A|8|Pass 
B|10|Fail 
C|25|Pass 
A|12|Fail 
C|26|Pass 
C|26|Fail"; 
    let lines = BufReader::new(Cursor::new(data)) 
     .lines() 
     .flat_map(Result::ok) 
     .flat_map(parse_line); 
    for ((fa, fb), s) in group(lines) { 
     println!("{}|{}|{}", fa, fb, s); 
    } 
} 

type ParsedLine = ((String, String), usize); 

fn parse_line(line: String) -> Option<ParsedLine> { 
    let mut fields = line 
     .split('|') 
     .map(str::trim); 
    if let (Some(fa), Some(fb), Some(fc)) = (fields.next(), fields.next(), fields.next()) { 
     fb.parse() 
      .ok() 
      .map(|v| ((fa.to_string(), fc.to_string()), v)) 
    } else { 
     None 
    } 
} 

fn group<I>(input: I) -> Vec<ParsedLine> where I: Iterator<Item = ParsedLine> { 
    let mut table = HashMap::new(); 
    for (k, v) in input { 
     let mut sum = table.entry(k).or_insert(0); 
     *sum += v; 
    } 
    let mut output: Vec<_> = table 
     .into_iter() 
     .collect(); 
    output.sort_by(|a, b| a.0.cmp(&b.0)); 
    output 
} 

playground link

HashMapはエントリをグループ化するために使用された後、結果がソートにVecに移動されます。

+2

@ swizard-私が錆びていることを少し覚えています。 – kit

関連する問題