Forward and current iterators - iterator

Is there was another way of writing this?
fn main() {
let mut a = [1, 2, 3, 4, 5];
let mut iter1 = a.iter();
let mut iter2 = a.iter().skip(1).peekable();
while iter2.peek().is_some() {
println!("iter1: {:?}, iter2: {:?}", iter1.next(), iter2.next());
}
}

I am not certain of what is the exact question but the code itself could be rewritten using the windows iterator:
fn main() {
let a = [1, 2, 3, 4, 5];
for w in a.windows(2) {
println!("elem1: {:?}, elem2: {:?}", w[0], w[1]);
}
}

Related

How can I make a typed index in Zig

I have an algorithm that has two arrays with their respective indices. Only, it would be very easy to mix both indices and access one of the arrays with the wrong index. For example:
var array1 = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var index1 = 7; // the 8th element in array1, fine because array1 has a length of 10
var array2 = [_]u8{ 1, 2, 3, 4, 5 };
var index2 = 2; // the 3rd element in array2, fine because array2 has a length of 5
array2[index1] // woops, I used the wrong index with the wrong array
Is there a way to make a custom index type to associate an array with a specific type of index such that indexing an array with the wrong type of index will result in a compile error?
Such as:
var array1 = [_:Index1]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; // with index type 'Index1'
var index1 : Index1 = 7; // index of type 'Index1'
var array2 = [_:Index2]u8{ 1, 2, 3, 4, 5 }; // with index type 'Index2'
var index2 : Index2 = 2; // index of type 'Index2'
array2[index1] // ERROR: array2 expects Index2 type index but Index1 type is used
const std = #import("std");
fn PickyArray(comptime T: type, n: usize, extra: anytype) type {
_ = extra;
return struct {
const Self = #This();
pub const Index = struct {
idx: usize,
};
unsafe_items: [n]T,
pub fn init(xs: [n]T) Self {
return .{.unsafe_items = xs};
}
pub fn get(self: Self, idx: Index) T {
return self.unsafe_items[idx.idx];
}
pub fn set(self: *Self, idx: Index, v: T) void {
self.unsafe_items[idx.idx] = v;
}
pub fn getPtr(self: Self, idx: Index) *T {
return &self.unsafe_items[idx.idx];
}
pub fn getSlice(self: Self, lo: Index, hi: Index) []T {
return self.unsafe_items[lo.idx..hi.idx];
}
};
}
const Array1 = PickyArray(u8, 10, "Index1");
const Index1 = Array1.Index;
const Array2 = PickyArray(u8, 5, "Index2");
const Index2 = Array2.Index;
pub fn main() void {
var array1 = Array1.init([_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
var index1 : Index1 = .{.idx=7}; // index of type 'Index1'
var array2 = Array2.init([_]u8{ 1, 2, 3, 4, 5 }); // with index type 'Index2'
var index2 : Index2 = .{.idx=2}; // index of type 'Index2'
_ = array2.get(index1); // ERROR: array2 expects Index2 type index but Index1 type is used
_ = array1;
_ = index1;
_ = array2;
_ = index2;
}
For extra credit, the type returned by getSlice should not be a normal slice and should refuse to accept integer indices.
Please do not do this.

How to apply a function to multiple columns of a polars DataFrame in Rust

I'd like to apply a user-define function which takes a few inputs (corresponding some columns in a polars DataFrame) to some columns of a polars DataFrame in Rust. The pattern that I'm using is as below. I wonder is this the best practice?
fn my_filter_func(col1: &Series, col2: &Series, col2: &Series) -> ReturnType {
let it = (0..n).map(|i| {
let col1 = match col.get(i) {
AnyValue::UInt64(val) => val,
_ => panic!("Wrong type of col1!"),
};
// similar for col2 and col3
// apply user-defined function to col1, col2 and col3
}
// convert it to a collection of the required type
}
You can downcast the Series to the proper type you want to iterate over, and then use rust iterators to apply your logic.
fn my_black_box_function(a: f32, b: f32) -> f32 {
// do something
a
}
fn apply_multiples(col_a: &Series, col_b: &Series) -> Float32Chunked {
match (col_a.dtype(), col_b.dtype()) {
(DataType::Float32, DataType::Float32) => {
let a = col_a.f32().unwrap();
let b = col_b.f32().unwrap();
a.into_iter()
.zip(b.into_iter())
.map(|(opt_a, opt_b)| match (opt_a, opt_b) {
(Some(a), Some(b)) => Some(my_black_box_function(a, b)),
_ => None,
})
.collect()
}
_ => panic!("unpexptected dtypes"),
}
}
Lazy API
You don't have to leave the lazy API to be able to access my_black_box_function.
We can collect the columns we want to apply in a Struct data type and then apply a closure over that Series.
fn apply_multiples(lf: LazyFrame) -> Result<DataFrame> {
df![
"a" => [1.0, 2.0, 3.0],
"b" => [3.0, 5.1, 0.3]
]?
.lazy()
.select([concat_lst(["col_a", "col_b"]).map(
|s| {
let ca = s.struct_()?;
let b = ca.field_by_name("col_a")?;
let a = ca.field_by_name("col_b")?;
let a = a.f32()?;
let b = b.f32()?;
let out: Float32Chunked = a
.into_iter()
.zip(b.into_iter())
.map(|(opt_a, opt_b)| match (opt_a, opt_b) {
(Some(a), Some(b)) => Some(my_black_box_function(a, b)),
_ => None,
})
.collect();
Ok(out.into_series())
},
GetOutput::from_type(DataType::Float32),
)])
.collect()
}
The solution I found working for me is with map_multiple(my understanding - this to be used if no groupby/agg) or apply_multiple(my understanding - whenerver you have groupby/agg). Alternatively, you could also use map_many or apply_many. See below.
use polars::prelude::*;
use polars::df;
fn main() {
let df = df! [
"names" => ["a", "b", "a"],
"values" => [1, 2, 3],
"values_nulls" => [Some(1), None, Some(3)],
"new_vals" => [Some(1.0), None, Some(3.0)]
].unwrap();
println!("{:?}", df);
//df.try_apply("values_nulls", |s: &Series| s.cast(&DataType::Float64)).unwrap();
let df = df.lazy()
.groupby([col("names")])
.agg( [
total_delta_sens().sum()
]
);
println!("{:?}", df.collect());
}
pub fn total_delta_sens () -> Expr {
let s: &mut [Expr] = &mut [col("values"), col("values_nulls"), col("new_vals")];
fn sum_fa(s: &mut [Series])->Result<Series>{
let mut ss = s[0].cast(&DataType::Float64).unwrap().fill_null(FillNullStrategy::Zero).unwrap().clone();
for i in 1..s.len(){
ss = ss.add_to(&s[i].cast(&DataType::Float64).unwrap().fill_null(FillNullStrategy::Zero).unwrap()).unwrap();
}
Ok(ss)
}
let o = GetOutput::from_type(DataType::Float64);
map_multiple(sum_fa, s, o)
}
Here total_delta_sens is just a wrapper function for convenience. You don't have to use it.You can do directly this within your .agg([]) or .with_columns([]) :
lit::<f64>(0.0).map_many(sum_fa, &[col("norm"), col("uniform")], o)
Inside sum_fa you can as Richie already mentioned downcast to ChunkedArray and .iter() or even .par_iter()
Hope that helps

How to merge objects with Lodash, but replace arrays values?

I'm trying to replace arrays of an old object with values from a new object which has arrays... I guess it will make sense when you see an example and desire result:
https://jsfiddle.net/redlive/9coq7dmu/
const oldValues = {
a: 1,
b: [2, 21, 22, 23],
c: {
d: 3,
e: 4,
f: [5, 6, 7]
}
};
const updatedValues = {
b: [],
c: {
f: [8]
}
}
const result = _.merge( oldValues, updatedValues );
console.log(result);
/* Desire result:
{
a: 1,
b: [],
c: {
d: 3,
e: 4,
f: [8]
}
}
*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>
Use _.mergeWith(), and if the 2nd value is an array, return it. If not return undefined, and let merge handle it:
const oldValues = {"a":1,"b":[2,21,22,23],"c":{"d":3,"e":4,"f":[5,6,7]}};
const updatedValues = {"b":[],"c":{"f":[8]}};
const result = _.mergeWith(oldValues, updatedValues, (a, b) =>
_.isArray(b) ? b : undefined
);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>

How to handle errors from the Read::read_to_end method?

I am reading a file and parsing the data:
fn main() {
parse_torrentfile("ubuntu-16.04.1-server-amd64.torrent");
}
fn parse_file(filename: &'static str) {
let mut f = File::open(&Path::new(filename)).unwrap();
let mut v: Vec<u8> = Vec::new();
let file_content = f.read_to_end(&mut v);
println!("{:?}", file_content);
}
If ubuntu-16.04.1-server-amd64.torrent is present, this works well, but if it isn't present, this error occurs:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { repr: Os { code: 2, message: "No such file or directory" } }'
How can I print "Not Exist File" or "process file parsing"?
You should be matching on the Result instead of calling unwrap() or expect(). Once you've got the error, you can either print it out or look at the ErrorKind if you want to handle different errors differently.
use std::fs::File;
use std::path::Path;
use std::io::Read;
fn main() {
parse_file("doesnt_exist.txt");
}
fn parse_file(filename: &'static str) {
let mut f = match File::open(&Path::new(filename)) {
Ok(f) => f,
Err(e) => {
use std::io::ErrorKind::*;
println!("Got error: {}", e);
match e.kind() {
NotFound => {
println!("File not found");
}
k => {
println!("Error: {:?}", k);
}
}
return;
}
};
let mut v: Vec<u8> = Vec::new();
let file_content = f.read_to_end(&mut v);
println!("{:?}", file_content);
}
Playground
Probably the most idiomatic approach would be propagating the result outside parse_file, printing the error in main.
use std::fs::File;
use std::io::{Read, Error as IoError};
use std::path::Path;
fn main() {
match parse_file("ubuntu-16.04.1-server-amd64.torrent") {
Err(e) => println!("{}", e),
_ => {}
}
}
fn parse_file(filename: &'static str) -> Result<(), IoError> {
let mut f = File::open(&Path::new(filename))?;
let mut v: Vec<u8> = Vec::new();
let file_content = f.read_to_end(&mut v);
println!("{:?}", file_content);
Ok(())
}
If you want to print the error in one line and then propagating it, you could do something like this instead:
fn main() {
parse_file("ubuntu-16.04.1-server-amd64.torrent");
}
fn parse_file(filename: &'static str) -> Result<(), IoError> {
let mut f = File::open(&Path::new(filename)).map_err(|e| {
println!("{}", e);
e
})?;
let mut v: Vec<u8> = Vec::new();
let file_content = f.read_to_end(&mut v);
println!("{:?}", file_content);
Ok(())
}

How can I test stdin and stdout?

I'd like to write a prompt function that sends a passed-in string to stdout and then returns the string that it reads from stdin. How could I test it?
Here is an example of the function:
fn prompt(question: String) -> String {
let mut stdin = BufferedReader::new(stdin());
print!("{}", question);
match stdin.read_line() {
Ok(line) => line,
Err(e) => panic!(e),
}
}
And here is my testing attempt
#[test]
fn try_to_test_stdout() {
let writer: Vec<u8> = vec![];
set_stdout(Box::new(writer));
print!("testing");
// `writer` is now gone, can't check to see if "testing" was sent
}
Use dependency injection. Coupling it with generics and monomorphism, you don't lose any performance:
use std::io::{self, BufRead, Write};
fn prompt<R, W>(mut reader: R, mut writer: W, question: &str) -> String
where
R: BufRead,
W: Write,
{
write!(&mut writer, "{}", question).expect("Unable to write");
let mut s = String::new();
reader.read_line(&mut s).expect("Unable to read");
s
}
#[test]
fn test_with_in_memory() {
let input = b"I'm George";
let mut output = Vec::new();
let answer = prompt(&input[..], &mut output, "Who goes there?");
let output = String::from_utf8(output).expect("Not UTF-8");
assert_eq!("Who goes there?", output);
assert_eq!("I'm George", answer);
}
fn main() {
let stdio = io::stdin();
let input = stdio.lock();
let output = io::stdout();
let answer = prompt(input, output, "Who goes there?");
println!("was: {}", answer);
}
In many cases, you'd want to actually propagate the error back up to the caller instead of using expect, as IO is a very common place for failures to occur.
This can be extended beyond functions into methods:
use std::io::{self, BufRead, Write};
struct Quizzer<R, W> {
reader: R,
writer: W,
}
impl<R, W> Quizzer<R, W>
where
R: BufRead,
W: Write,
{
fn prompt(&mut self, question: &str) -> String {
write!(&mut self.writer, "{}", question).expect("Unable to write");
let mut s = String::new();
self.reader.read_line(&mut s).expect("Unable to read");
s
}
}
#[test]
fn test_with_in_memory() {
let input = b"I'm George";
let mut output = Vec::new();
let answer = {
let mut quizzer = Quizzer {
reader: &input[..],
writer: &mut output,
};
quizzer.prompt("Who goes there?")
};
let output = String::from_utf8(output).expect("Not UTF-8");
assert_eq!("Who goes there?", output);
assert_eq!("I'm George", answer);
}
fn main() {
let stdio = io::stdin();
let input = stdio.lock();
let output = io::stdout();
let mut quizzer = Quizzer {
reader: input,
writer: output,
};
let answer = quizzer.prompt("Who goes there?");
println!("was: {}", answer);
}