Csv 如何在Rust中读取和处理管道分隔文件?

Csv 如何在Rust中读取和处理管道分隔文件?,csv,rust,data-processing,Csv,Rust,Data Processing,我想读取管道分隔文件,处理数据,并生成CSV格式的结果 输入文件数据 A | 1 |通行证 B | 2 |失败 A | 3 |失败 C | 6 |通道 A | 8 |通行证 B | 10 |失败 C | 25 |通行证 A | 12 |失败 C | 26 |通道 C | 26 |失败 我想在第1列和第3列上应用GROUPBY函数,并根据特定的组生成第2列的和 我被困在如何维护记录以应用分组功能的问题上: use std::fs::File; use std::io::{BufReader};

我想读取管道分隔文件,处理数据,并生成CSV格式的结果

输入文件数据

A | 1 |通行证
B | 2 |失败
A | 3 |失败
C | 6 |通道
A | 8 |通行证
B | 10 |失败
C | 25 |通行证
A | 12 |失败
C | 26 |通道
C | 26 |失败
我想在第1列和第3列上应用GROUPBY函数,并根据特定的组生成第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、 失败,15
A、 通过,9
B、 失败,12
C、 失败,26
C、 通过,57

是否有任何特定的技术可以读取管道分隔文件并像上面那样处理数据?Python的pandas实现了这一要求,但我想在Rust中实现这一点。

我建议这样做:

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
}
使用std::str;
使用std::collections::HashMap;
使用std::io::{BufReader,BufRead,Cursor};
fn main(){
让数据=”
A | 1 |通行证
B | 2 |失败
A | 3 |失败
C | 6 |通道
A | 8 |通行证
B | 10 |失败
C | 25 |通行证
A | 12 |失败
C | 26 |通道
C | 26 |失败”;
let line=BufReader::new(光标::new(数据))
.行()
.flat_映射(结果::确定)
.平面图(解析线);
对于组(行)中的((fa,fb),s){
println!(“{}{}}{}}{}”,fa、fb、s);
}
}
类型ParsedLine=((字符串,字符串),usize);
fn parse_line(line:String)->选项{
让mut字段=行
.split(“|”)
.map(str::trim);
如果let(一些(fa),一些(fb),一些(fc))=(fields.next(),fields.next(),fields.next()){
fb.parse()
.ok()
.map(|v |((fa.to_string(),fc.to_string()),v))
}否则{
没有一个
}
}
fn组(输入:I)->Vec,其中I:迭代器{
让mut table=HashMap::new();
对于输入中的(k,v){
让mut sum=表项(k)或插入(0);
*总和+=v;
}
让mut输出:Vec=表
.into_iter()
.收集();
output.sort_by(| a,b | a.0.cmp(&b.0));
输出
}


这里使用
HashMap
对条目进行分组,然后将结果移动到
Vec
进行排序。

我建议这样做:

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
}
使用std::str;
使用std::collections::HashMap;
使用std::io::{BufReader,BufRead,Cursor};
fn main(){
让数据=”
A | 1 |通行证
B | 2 |失败
A | 3 |失败
C | 6 |通道
A | 8 |通行证
B | 10 |失败
C | 25 |通行证
A | 12 |失败
C | 26 |通道
C | 26 |失败”;
let line=BufReader::new(光标::new(数据))
.行()
.flat_映射(结果::确定)
.平面图(解析线);
对于组(行)中的((fa,fb),s){
println!(“{}{}}{}}{}”,fa、fb、s);
}
}
类型ParsedLine=((字符串,字符串),usize);
fn parse_line(line:String)->选项{
让mut字段=行
.split(“|”)
.map(str::trim);
如果let(一些(fa),一些(fb),一些(fc))=(fields.next(),fields.next(),fields.next()){
fb.parse()
.ok()
.map(|v |((fa.to_string(),fc.to_string()),v))
}否则{
没有一个
}
}
fn组(输入:I)->Vec,其中I:迭代器{
让mut table=HashMap::new();
对于输入中的(k,v){
让mut sum=表项(k)或插入(0);
*总和+=v;
}
让mut输出:Vec=表
.into_iter()
.收集();
output.sort_by(| a,b | a.0.cmp(&b.0));
输出
}

这里使用
HashMap
对条目进行分组,然后将结果移动到
Vec
进行排序。

如前所述,使用来完成解析文件的繁重工作。然后,只需使用一个能有效执行排序的函数对每一行进行分组。帮助有效地插入到
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、 失败,15
A、 通过,9
B、 失败,12
C、 失败,26
C、 通过,57
如前所述,使用来完成解析文件的繁重工作。然后,只需使用一个能有效执行排序的函数对每一行进行分组。帮助有效地插入到
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、 失败,15
A、 通过,9
B、 失败,12
C、 失败,26
C、 通过,57

是否使用csv板条箱?使用csv板条箱@swizard-你能解释一下我不熟悉的小代码吗。@swizard-你能解释一下我不熟悉的小代码吗。@Shepmaster-我怎么能把这个结果推到像output.csv这样的csv文件中?@Shepmaster-是的。知道了。谢谢你的帮助。@Shepmaster-我如何能将这个结果推送到像output.csv这样的csv文件中?@Shepmaster-是的。知道了。谢谢你的帮助。