Programatically creating an iterator from mapping functions in Rust - function

I'm trying to write code like the following, but where I apply f1 and f2 some variable number of times:
#![feature(impl_trait_in_bindings)]
fn f1(c: char) -> impl IntoIterator<Item = char> {
vec!['A', c]
}
fn f2(c: char) -> impl IntoIterator<Item = char> {
vec!['C', 'D', c]
}
fn main() {
let x = vec!['X', 'X', 'X'];
let v: impl Iterator<Item = char> = x.into_iter();
let v = v.flat_map(f1);
let v = v.flat_map(f2);
println!("Force evaluation of five elements: {:?}", v.take(5).collect::<Vec<_>>());
}
I'd like to replace the let v = ... lines with a loop that iteratively reassigns v, like
let mut v: impl Iterator<Item = char> = x.into_iter();
for i in 0..f1Times {
v = v.flat_map(f1);
}
for i in 0..f2Times {
v = v.flat_map(f2);
}
... e.g. for my use case I may have several functions and I won't know which ones (or how many times) to apply ahead of time. I'd like the result to be an iterator that I can take only a limited number of items from, and I'd like to avoid invoking any functions that aren't needed to generate those items.
I can't get the types to work. For instance with the let mut block I proposed above I get:
mismatched types
expected opaque type `impl Iterator`
found struct `FlatMap<impl Iterator, impl IntoIterator, fn(char) -> impl IntoIterator {f1}>`
Is there a good way to build up this sort of iterator programatically?

I've found this pattern works, but still don't know if it's idiomatic or recommended...
#![feature(impl_trait_in_bindings)]
fn f1(c: char) -> impl Iterator<Item = char> {
Box::new(vec!['A', c].into_iter())
}
fn f2(c: char) -> impl Iterator<Item = char> {
Box::new(vec!['C', 'D', c].into_iter())
}
fn main() {
let x = vec!['X', 'X', 'X'];
let mut v: Box<dyn Iterator<Item = char>> = Box::new(x.into_iter());
let f1_ntimes = 2;
for _i in 0..f1NTimes {
v = Box::new(v.into_iter().flat_map(f1));
}
let f2_ntimes = 2;
for _i in 0..f2_ntimes {
v = Box::new(v.into_iter().flat_map(f2));
}
println!("Force evaluation of five elements: {:?}", v.take(5).collect::<Vec<_>>());
}

Related

How to define function that returns Struct<Fn> [duplicate]

This question already has answers here:
Returning a closure from a method of a generic struct
(2 answers)
Closed 8 months ago.
I have a struct
struct A<F: Fn(i32)->i32>
How to define function which return it like
fn some_function() -> A<Fn(i32)->i32>
?
I think you need to use the fn type instead of the Fn trait:
struct A(fn(i32) -> i32);
fn some_function() -> A {
let square = |x| x * x;
A(square)
}
fn main() {
let f = some_function();
println!("{}", f.0(7));
}
49
You can of course also use the Fn trait, but then you need to use the impl keyword:
struct A<T: Fn(i32) -> i32>(T);
fn some_function() -> A<impl Fn(i32) -> i32> {
let square = |x| x * x;
A(square)
}
fn main() {
let f = some_function();
println!("{}", f.0(7));
}
49
impl here means "this is a type that I don't want to write here completely, but believe me, it implements Fn(i32) -> i32".

How do I write a function that returns itself?

What I want to make is a function, that returns itself, so I can call it like this:
foo()()...()
In C# it would be done via delegates:
delegate SelfFunc SelfFunc();
static void Main() {
SelfFunc foo = null;
foo = () => {
return foo;
};
foo()()...();
}
Anticipating questions like "why implement such silly behavior?": I want to sum numbers in a very strange way using single function continues calls: foo(1)(2)(3)() = 6, but in this question I just want to know how to return function itself. Example realization of this method that I made in C#. This is all just for fun and to learn Rust:
static int sum = 0;
delegate dynamic InfFunc(int i = int.MaxValue);
static void InfFuncTest() {
InfFunc f = null;
f = (int i) => {
if(i == int.MaxValue) {
return sum;
}
sum += i;
return f;
};
var g = f;
var value = g(1)(2)(3)();
Console.WriteLine(value);
}
A function that returns itself is possible on nightly.
First you need to enable the features unboxed_closures and fn_traits.
Then you can define a struct which, when called, returns self. The full code looks something like this:
#![feature(unboxed_closures, fn_traits)]
struct SelfFunc;
impl FnOnce<()> for SelfFunc {
type Output = SelfFunc;
extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
self
}
}
Then you can call the function as many times as you want:
fn main() {
let f = SelfFunc;
f()()()()()();
}
Based on #cameron1024's answer, you can "overload" using traits, but you will need 2 structs to handle the empty case properly of foo() (here called Add) without any arguments returning 0.
#![feature(unboxed_closures, fn_traits)]
struct Add;
impl FnOnce<(u32,)> for Add {
type Output = AddImpl;
extern "rust-call" fn call_once(self, args: (u32,)) -> Self::Output {
AddImpl(args.0)
}
}
impl FnOnce<()> for Add {
type Output = u32;
extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
0
}
}
struct AddImpl(u32);
impl FnOnce<()> for AddImpl {
type Output = u32;
extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
self.0
}
}
impl FnOnce<(u32,)> for AddImpl {
type Output = AddImpl;
extern "rust-call" fn call_once(self, args: (u32,)) -> Self::Output {
Self(self.0 + args.0)
}
}
fn main() {
dbg!( Add(1)(2)(3)() );
dbg!( Add() );
}
Playground
If you do not care about the no-args foo() requirement, you can make Add a tuple struct instead and remove AddImpl:
#![feature(unboxed_closures, fn_traits)]
struct Add(u32);
impl FnOnce<(u32,)> for Add {
type Output = Add;
extern "rust-call" fn call_once(self, args: (u32,)) -> Self::Output {
Add(self.0 + args.0)
}
}
impl FnOnce<()> for Add {
type Output = u32;
extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
self.0
}
}
fn main() {
dbg!( Add(1)(2)(3)() );
//dbg!( Add() ); // doesn't compile
}
Playground
Although I should note that this likely isn't such a great idea, using an slice/iterator would likely result in cleaner code:
fn main() {
dbg!([1, 2, 3].iter().copied().sum::<u32>());
}
Playground

Reading CSV with list valued columns in rust

I'm trying to use csv and serde to read a mixed-delimiter csv-type file in rust, but I'm having a hard time seeing how to use these libraries to accomplish it. Each line looks roughly like:
value1|value2|subvalue1,subvalue2,subvalue3|value4
and would de-serialize to a struct that looks like:
struct Line {
value1:u64,
value2:u64,
value3:Vec<u64>,
value4:u64,
}
Any guidance on how to tell the library that there are two different delimiters and that one of the columns has this nested structure?
Ok, I'm still a beginner in Rust so I can't guarantee that this is good at all- I suspect it could be done more efficiently, but I do have a solution that works-
use csv::{ReaderBuilder};
use serde::{Deserialize, Deserializer};
use serde::de::Error;
use std::error::Error as StdError;
#[derive(Debug, Deserialize)]
pub struct ListType {
values: Vec<u8>,
}
fn deserialize_list<'de, D>(deserializer: D) -> Result<ListType , D::Error>
where D: Deserializer<'de> {
let buf: &str = Deserialize::deserialize(deserializer)?;
let mut rdr = ReaderBuilder::new()
.delimiter(b',')
.has_headers(false)
.from_reader(buf.as_bytes());
let mut iter = rdr.deserialize();
if let Some(result) = iter.next() {
let record: ListType = result.map_err(D::Error::custom)?;
return Ok(record)
} else {
return Err("error").map_err(D::Error::custom)
}
}
struct Line {
value1:u64,
value2:u64,
#[serde(deserialize_with = "deserialize_list")]
value3:ListType,
value4:u64,
}
fn read_line(line: &str) -> Result<Line, Box<dyn StdError>> {
let mut rdr = ReaderBuilder::new()
.delimiter(b'|')
.from_reader(line.as_bytes());
let mut iter = rdr.deserialize();
if let Some(result) = iter.next() {
let record: Line = result?;
return Ok(Line)
} else {
return Err(From::from("error"));
}
}
[EDIT]
I found that the above solution was intolerably slow, but I was able to make performance acceptable by simply manually deserializing the nested type into a fixed size array by-
#[derive(Debug, Deserialize)]
pub struct ListType {
values: [Option<u8>; 8],
}
fn deserialize_farray<'de, D>(deserializer: D) -> Result<ListType, D::Error>
where
D: Deserializer<'de>,
{
let buf: &str = Deserialize::deserialize(deserializer)?;
let mut split = buf.split(",");
let mut dest: CondList = CondList {
values: [None; 8],
};
let mut ind: usize = 0;
for tok in split {
if tok == "" {
break;
}
match tok.parse::<u8>() {
Ok(val) => {
dest.values[ind] = Some(val);
}
Err(e) => {
return Err(e).map_err(D::Error::custom);
}
}
ind += 1;
}
return Ok(dest);
}

How to read and process a pipe delimited file in Rust?

I want to read a pipe delimited file, process the data, and generate a result in CSV format.
Input file 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
I'm want to apply a group by function on column 1 and column 3 and generate column 2's sum according to a particular group.
I'm stuck at the point of how to maintain the records to apply the group by function:
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;
}
}
}
I'm expecting a result like:
name,result,num
A,Fail,15
A,Pass,9
B,Fail,12
C,Fail,26
C,Pass,57
Is there any specific technique to read a pipe-delimited file and process the data like above? Python's pandas accomplished this requirement but I want to do it in Rust.
As was mentioned, use the csv crate to do the heavy lifting of parsing the file. Then it's just a matter of grouping each row by using a BTreeMap which also helpfully performs sorting. The entry API helps efficiently insert into the 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);
}
}
You'll note that the output is correct:
name,result,num
A,Fail,15
A,Pass,9
B,Fail,12
C,Fail,26
C,Pass,57
I'd suggest something like this:
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
Here a HashMap is used for grouping entries and then results are moved to a Vec for sorting.

How to pass a function as argument in Rust

Given the following rust program:
fn call_twice<A>(val: A, f: fn(A) -> A) -> A {
f(f(val))
}
fn main() {
fn double(x: int) -> int {x + x};
println!("Res is {}", call_twice(10i, double));
// println!("Res is {}", call_twice(10i, (x: int) -> int {x + x}));
// ^ this line will fail
}
Why can I pass double as the function, but not inlined? What is a good way to achieve the same behaviour without defining the function somewhere?
2016-04-01 Update:
As of Rust 1.0, the code should look like this:
fn call_twice<A, F>(val: A, mut f: F) -> A
where F: FnMut(A) -> A {
let tmp = f(val);
f(tmp)
}
fn main() {
fn double(x: i32) -> i32 {x + x};
println!("Res is {}", call_twice(10, double));
println!("Res is {}", call_twice(10, |x| x + x));
}
The change to the closure parameter is because closure are now unboxed.
Original:
Insofar as I know, you can't define functions inline like that.
What you want is a closure. The following works:
fn call_twice<A>(val: A, f: |A| -> A) -> A {
let tmp = f(val);
f(tmp)
}
fn main() {
fn double(x: int) -> int {x + x};
println!("Res is {}", call_twice(10i, double));
println!("Res is {}", call_twice(10i, |x| x + x));
}
There are a few things to note:
Functions coerce to closures, but the opposite isn't true.
You need to store the result of f(val) in a temporary due to borrowing rules. Short version: you need unique access to a closure to call it, and the borrow checker isn't quite clever enough to realise the two calls are independent in their original positions.
Closures are in the process of being replaced by unboxed closures, so this will change in the future, but we're not quite there yet.