This outputs the raw and GZip compressed length line by line as a way to estimate string complexity:
use std::fs::File;
use std::io::{BufReader, BufRead, Read};
use flate2::{read, Compression};
fn main() {
let mut f = File::open("/etc/passwd").unwrap();
let mut f = BufReader::new(f);
let mut _buf = vec![0u8; 100];
for line in f.lines() {
let l = line.unwrap();
let p = l.as_bytes().len();
let mut e = read::GzEncoder::new(l.as_bytes(), Compression::default());
let q = e.read(&mut _buf).unwrap();
println!("raw = {}, zip = {}", p, q);
}
}
I suspect that calling GzEncoder::new in every iteration might be expensive and want to move it outside the loop. How do I do that using flate2?
Related
This question already has answers here:
How to handle "borrowed value does not live long enough" error when finding the longest substring of consecutive equal characters?
(2 answers)
Closed last month.
Suppose I have a char in the variable c and a positive int in the variable n. I want to build the str containing c occurring n times. How can I do it?
I tried building it as a String, and maybe I just got dizzy trying to read the documentation on strings, but I couldn't see how to convert it to a str. But then if I'm trying to just build it as a str directly then I couldn't see how to do that either.
For context, here is the full function I'm trying to implement. It takes a string and finds the longest sequence of consecutive characters (and breaks ties by taking the first that occurs).
pub fn longest_sequence(s: &str) -> Option<&str> {
if s.len() == 0 { return None; }
let mut current_c = s.as_bytes()[0] as char;
let mut greatest_c = s.as_bytes()[0] as char;
let mut current_num = 0;
let mut greatest_num = 0;
for ch in s.chars() {
if current_c == ch {
current_num += 1;
if current_num > greatest_num {
greatest_num = current_num;
greatest_c = current_c;
}
} else {
current_num = 1;
current_c = ch;
}
}
// Now build the output str ...
}
I think there are a couple of misconceptions about str vs String.
str can never exist alone. It is always used as &str (or Box<str> or *str, but in your case those shouldn't matter).
&str does not own any data. It is merely a reference to (parts of) another String.
String actually holds data.
So when you want to return data, use String; if you want to reference existing data, return &str.
There is no way to convert a local String to a &str. Somewhere the data has to be stored, and &str doesn't store it. (for completeness sake: Yes you could leak it, but that would create a permanent string in memory that will never go away again)
So in your case there are two ways:
Reference the input &str, because somewhere its data is already stored.
Return a String instead.
As a side note: do not do s.as_bytes()[0] as char, as it will not work with UTF8-strings. Rust strings are defined as UTF8.
Here is one possible solution:
pub fn longest_sequence(s: &str) -> Option<&str> {
let mut current_c = s.chars().next()?;
let mut current_start = 0;
let mut current_len = 0;
let mut greatest: &str = "";
let mut greatest_len = 0;
for (pos, ch) in s.char_indices() {
if current_c == ch {
current_len += 1;
} else {
if greatest_len < current_len {
greatest = &s[current_start..pos];
greatest_len = current_len;
}
current_len = 1;
current_c = ch;
current_start = pos;
}
}
if greatest_len < current_len {
greatest = &s[current_start..];
}
Some(greatest)
}
pub fn main() {
let s = "ðĪŠððððâŽâŽðĪŠðĪŠ";
let seq = longest_sequence(s);
println!("{:?}", seq);
}
Some("ððð")
Some explanations:
No need to check for empty string. s.chars().next()? does so automatically.
Use s.chars().next() instead of s.as_bytes()[0] as char, as the second one is not UTF8 compatible.
I explicitely store greatest_len instead of using greatest.len() because greatest.len() is also not UTF8 compatible as it gives you the size of the string in bytes, not in chars.
You stored the new largest string whenever a new char of the same value was found; I had to move it to the case where the char type changed (and once after the loop), because we don't yet know the end of the current char. Again, note that &s[current_start..current_start+current_len] wouldn't work, because &s[ .. ] wants indices in bytes, but current_len is in chars. So we need to wait for another char to know where the previous one ended.
Another solution, based on your code, would be:
pub fn longest_sequence(s: &str) -> Option<String> {
let mut current_c = s.chars().next()?;
let mut greatest_c = current_c;
let mut current_num = 0;
let mut greatest_num = 0;
for ch in s.chars() {
if current_c == ch {
current_num += 1;
if current_num > greatest_num {
greatest_num = current_num;
greatest_c = current_c;
}
} else {
current_num = 1;
current_c = ch;
}
}
// Build the output String
Some(std::iter::repeat(greatest_c).take(greatest_num).collect())
}
pub fn main() {
let s = "ðĪŠððððâŽâŽðĪŠðĪŠ";
let seq = longest_sequence(s);
println!("{:?}", seq);
}
Some("ððð")
To convert a String to &'static str you need to leak it like this:
fn leak(s: String) -> &'static str {
let ptr = s.as_str() as *const str;
core::mem::forget(s);
unsafe {&*ptr}
}
And char to String:
fn cts(c: char, n: usize) -> String {
(0..n)
.map(|_| c)
.collect()
}
So char to &'static str basically will look like this:
fn conv(c: char, n: usize) -> &'static str {
leak(cts(c, n))
}
I do not recommend to leak the String tho, just use it as is.
for mut i in 0..448 {
i += 179;
println!("{}", i)
How can I add all of the values that get printed to the terminal when this is ran?
fn main() {
let a = 179..627;
let sum: i32 = a.into_iter().sum();
println!("the total sum is: {}", sum);
this worked
I need to pass a reference to an array of references to arrays (or slice of slices) to the following function in Rust
const LNGTH: usize = 5;
fn swap_array<T>(x: &mut [&[T; LNGTH]]) {
let temp = x[1];
x[1] = x[0];
x[0] = temp;
}
The problem is that it seems I have to specify an array length for the "inner" arrays (here: LNGTH).
So, the following code works fine:
fn main() {
let x_array: [i32; LNGTH] = [5,2,8,9,1];
let x_other: [i32; LNGTH] = [6,7,6,7,6];
let mut y_array: [&[i32; LNGTH]; 2] = [&x_array, &x_other];
println!("before : {:?}", y_array);
swap_array(&mut y_array);
println!("after : {:?}", y_array);
}
But if I change the signature of swap_array to fn swap_array<T>(x: &mut [&[T]]), I get the following error:
error[E0308]: mismatched types
--> src/main.rs:14:16
|
14 | swap_array(&mut y_array[..]);
| ^^^^^^^^^^^^^^^^ expected slice, found array of 5 elements
|
= note: expected type `&mut [&[_]]`
found type `&mut [&[i32; 5]]`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.
error: Could not compile `tut_arrays`.
From the perspective of C, I would like to have a function that accepts arguments of type T**. A corresponding function in C would look like that
void swap_arrays(my_type ** x) {
my_type* temp = x[1];
x[1] = x[0];
x[0] = temp;
}
Here is a slice-of-slices version:
const LEN: usize = 5;
fn swap_array<T>(x: &mut [&[T]]) {
let temp = x[1];
x[1] = x[0];
x[0] = temp;
}
fn main() {
let x_array: [i32; LEN] = [5, 2, 8, 9, 1];
let x_other: [i32; LEN] = [6, 7, 6, 7, 6];
let mut y_array: [&[i32]; 2] = [&x_array, &x_other];
println!("before : {:?}", y_array);
swap_array(&mut y_array);
println!("after : {:?}", y_array);
}
You have to change the formal argument to slice of slices, and the elements of y_array must be slices, too (the latter is basically what the error message said).
Since arr is borrowed as mutable, the length of arr can't be gotten by calling len(). I'm stuck here, what's the right way to do it?
fn double_last(arr: &mut[i32]) -> &i32 {
let last = &mut arr[arr.len() - 1]; // borrow checker error.
//let last = &mut arr[3]; // fine
*last *= 2;
last
}
fn main() {
let mut a = [1,2,3,4];
println!("{}", double_last(&mut a));
println!("{:?}", a);
}
If you only need the last, you can use std::slice::last_mut
fn double_last(arr: &mut[i32]) -> &i32 {
let last = arr.last_mut().unwrap();
*last *= 2;
last
}
This will hopefully be fixed with the introduction of non-lexical lifetimes and the accompanying changes soon into the future (seems like it could be solved?).
For now though, you can satisfy the borrow checker by splitting that calculation out:
let n = arr.len() - 1;
let last = &mut arr[n];
File example; square matrix; size of matrix after #
#3
1.1 -0.2 0.1
0.1 -1.2 -0.2
0.2 -0.1 1.1
Approximately so i would write it in C
double **A;
int i,j,size=0;
FILE *f=NULL;
f=fopen("input.txt","w");
fscanf(f,"#%d\n",&size);
A=(double**)malloc(size*sizeof(double*));
for(i=0;i<size;i++)
A[i]=(double*)malloc(size*sizeof(double));
for(i=0;i<size;i++)
{
for(j=0;j<size;j++)
{
fscanf(f,"%lf",&A[i][j]);
}
}
fclose(f);
I tried to use the method "read_to_string" and parse String, but I'm confused by the conversion between String and str.
This is a naive translation of your code to Rust:
use std::fs::File;
use std::io::{BufRead, BufReader};
fn main() {
// open the file
let mut f = BufReader::new(File::open("input.txt").unwrap());
// read the first line and extract the number from it
let mut num_line = String::new();
f.read_line(&mut num_line).unwrap();
let n: usize = num_line[1..].trim().parse().unwrap();
// preallocate the array and read the data into it
let mut arr = vec![vec![0f64; n]; n];
for (i, line) in f.lines().enumerate() {
for (j, number) in line.unwrap().split(char::is_whitespace).enumerate() {
arr[i][j] = number.trim().parse().unwrap();
}
}
println!("{:?}", arr);
}
There is more idiomatic way to perform the loop in Rust, though:
use std::fs::File;
use std::io::{BufRead, BufReader};
fn main() {
let mut f = BufReader::new(File::open("input.txt").unwrap());
let mut num_line = String::new();
f.read_line(&mut num_line).unwrap();
let n: usize = num_line[1..].trim().parse().unwrap();
let arr: Vec<Vec<f64>> = f.lines()
.take(n)
.map(|l| l.unwrap().split(char::is_whitespace)
.take(n)
.map(|number| number.parse().unwrap())
.collect())
.collect();
println!("{:?}", arr);
}
In fact, you don't even need the number of lines in advance to read the data if the format of your file is completely fixed:
use std::fs::File;
use std::io::{BufRead, BufReader};
fn main() {
let mut f = BufReader::new(File::open("input.txt").unwrap());
let mut s = String::new();
f.read_line(&mut s).unwrap();
let arr: Vec<Vec<f64>> = f.lines()
.map(|l| l.unwrap().split(char::is_whitespace)
.map(|number| number.parse().unwrap())
.collect())
.collect();
println!("{:?}", arr);
}