How to bruteforce a string match effectively? - performance

I have this code that does a brute-force search to find a match for a string:
fn main() {
let strings: Vec<String> = ["a", "b", "c","d","e","f","g","h","i","j","K","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"].map(String::from).to_vec();
for i in strings.iter(){
for j in strings.iter(){
for k in strings.iter(){
for l in strings.iter(){
let mut result = format!("{i}{j}{k}{l}");
println!("{}",result);
if result == "Kaio"{
println!("Found it!!");
return ;
}
}
}
}
}
}
Is there a better way to be doing this? Can I do it dynamically? In this example I use four loops, assuming that the final string has a length of four. But what if there's a dynamically-sized string that I don't know the size of?

The itertools crate gives a good macro to generate this in iproduct.
use itertools::iproduct;
fn main() {
let pool: Vec<String> = "abcdefghijklmnopqrstuvwxyz".chars().map(String::from).collect();
let possibilities: Vec<String> = iproduct!(&pool, &pool, &pool, &pool) // for four-letters
.map(|(a, b, c, d)| format!("{}{}{}{}", a, b, c, d))
.collect();
for password in possibilities {
if password == "eggs" {
println!("We found it!");
}
}
}

Related

Rust error expected type `()` found type `(i32, i32)`

Pretty new to Rust, decided to brush up using the Advent of Code 2020 Day 1 Puzzle. I'm using the following function:
fn find_numbers_2020(v: Vec<i32>) -> (i32,i32) {
let mut n1: i32 = 0;
let mut n2: i32 = 0;
let mut cnt = 0;
let size = v.len();
for v_i in v {
n1 = v_i;
cnt = cnt+1;
for i in cnt..size {
if (n1 + *v.get(i).unwrap()) == 2020 {
n2 = *v.get(i).unwrap();
(n1, n2) //Issue is here
}
}
}
(n1, n2)
}
But I get the error
"32 (n1, n2)
^^^^^^^^ expected (), found tuple.
It's being called from main as follows
fn main() {
let filename = String::from("./input.txt");
let v = parse_file(filename); //This works fine
for v_i in v {
println!("{}", v_i);
}
let result = find_numbers_2020(v);
let (n1, n2) = result;
println!("{} + {} = {}", n1, n2, n1+n2);
println!("{} * {} = {}", n1, n2, n1*n2);
}
I should also mention that v is a Vec<i32>. Sorry for the beginner question but Rust can be a little confusing and I haven't been able to find any answers through googling.
You can omit the return keyword only if the returned value is the last expression in the function block, otherwise you need to explicitly use return. Adding return to your example fixes that particular error but a bunch of new ones come up in its place. This is how I'd write the function:
fn find_numbers_2020(v: Vec<i32>) -> (i32, i32) {
for (skip, &n1) in v.iter().enumerate() {
for &n2 in v.iter().skip(skip) {
if n1 + n2 == 2020 {
return (n1, n2);
}
}
}
panic!("no pair of numbers in vec sum to 2020");
}
This is one of those cases where you need to use a return expression. Your initial for loop also consumes v, so to be able to do v.get() in the inner loop, you need to borrow v instead, i.e. &v or v.iter().
fn find_numbers_2020(v: Vec<i32>) -> (i32, i32) {
let mut n1: i32 = 0;
let mut n2: i32 = 0;
let mut cnt = 0;
let size = v.len();
for &v_i in &v {
n1 = v_i;
cnt = cnt + 1;
for i in cnt..size {
if (n1 + *v.get(i).unwrap()) == 2020 {
n2 = *v.get(i).unwrap();
return (n1, n2);
}
}
}
(n1, n2)
}
This is also a perfect case of when you could return an Option and use an if let expression. So instead of returning (i32, i32) then you would return Option<(i32, i32)>.
Instead of doing *v.get(i).unwrap(), then you can also just index v, i.e. v[i].
fn find_numbers_2020(v: Vec<i32>) -> Option<(i32, i32)> {
let mut cnt = 0;
for &n1 in &v {
cnt += 1;
for i in cnt..v.len() {
if (n1 + v[i]) == 2020 {
let n2 = v[i];
return Some((n1, n2));
}
}
}
None
}
fn main() {
// ...
if let Some((n1, n2)) = result {
println!("{} + {} = {}", n1, n2, n1 + n2);
println!("{} * {} = {}", n1, n2, n1 * n2);
}
}
Instead of manually incrementing indices, you can use enumerate() in the first loop, then in the second loop you can use skip(i + 1) with the index returned by enumerate().
fn find_numbers_2020(v: Vec<i32>) -> Option<(i32, i32)> {
for (i, &n1) in v.iter().enumerate() {
for &n2 in v.iter().skip(i + 1) {
if (n1 + n2) == 2020 {
return Some((n1, n2));
}
}
}
None
}
Instead of v: Vec<i32>, it would be more idiomatic to use a slice, i.e. v: &[i32]. In main() you just have to borrow v in your find_numbers_2020() call, i.e. find_numbers_2020(&v)

What's the most straightforward way to chain comparisons, yielding the first non-equal?

It's quite common to compare data with precedence, for a struct which has multiple members which can be compared, or for a sort_by callback.
// Example of sorting a: Vec<[f64; 2]>, sort first by y, then x,
xy_coords.sort_by(
|co_a, co_b| {
let ord = co_a[1].cmp(&co_b[1]);
if ord != std::cmp::Ordering::Equal {
ord
} else {
co_a[0].cmp(&co_b[0])
}
}
);
Is there a more straightforward way to perform multiple cmp functions, where only the first non-equal result is returned?
perform multiple cmp functions, where only the first non-equal result is returned
That's basically how Ord is defined for tuples. Create a function that converts your type into a tuple and compare those:
fn main() {
let mut xy_coords = vec![[1, 0], [-1, -1], [0, 1]];
fn sort_key(coord: &[i32; 2]) -> (i32, i32) {
(coord[1], coord[0])
}
xy_coords.sort_by(|a, b| {
sort_key(a).cmp(&sort_key(b))
});
}
Since that's common, there's a method just for it:
xy_coords.sort_by_key(sort_key);
It won't help your case, because floating point doesn't implement Ord.
One of many possibilities is to kill the program on NaN:
xy_coords.sort_by(|a, b| {
sort_key(a).partial_cmp(&sort_key(b)).expect("Don't know how to handle NaN")
});
See also
Using max_by_key on a vector of floats
How to do a binary search on a Vec of floats?
There are times when you may not want to create a large tuple to compare values which will be ignored because higher priority values will early-exit the comparison.
Stealing a page from Guava's ComparisonChain, we can make a small builder that allows us to use closures to avoid extra work:
use std::cmp::Ordering;
struct OrdBuilder<T> {
a: T,
b: T,
ordering: Ordering,
}
impl<T> OrdBuilder<T> {
fn new(a: T, b: T) -> OrdBuilder<T> {
OrdBuilder {
a: a,
b: b,
ordering: Ordering::Equal,
}
}
fn compare_with<F, V>(mut self, mut f: F) -> OrdBuilder<T>
where F: for <'a> FnMut(&'a T) -> V,
V: Ord,
{
if self.ordering == Ordering::Equal {
self.ordering = f(&self.a).cmp(&f(&self.b));
}
self
}
fn finish(self) -> Ordering {
self.ordering
}
}
This can be used like
struct Thing {
a: u8,
}
impl Thing {
fn b(&self) -> u8 {
println!("I'm slow!");
42
}
}
fn main() {
let a = Thing { a: 0 };
let b = Thing { a: 1 };
let res = OrdBuilder::new(&a, &b)
.compare_with(|x| x.a)
.compare_with(|x| x.b())
.finish();
println!("{:?}", res);
}

Speedup counter game

I'm trying to solve a Rust algorithm question on hackerrank. My answer times out on some of the larger test cases. There are about 5 people who've completed it, so I believe it is possible and I assume they compile in release mode. Is there any speed-ups I'm missing?
The gist of the game is a counter (inp in main) is conditionally reduced and based on who can't reduce it any more, the winner is chosen.
use std::io;
fn main() {
let n: usize = read_one_line().
trim().parse().unwrap();
for _i in 0..n{
let inp: u64 = read_one_line().
trim().parse().unwrap();
println!("{:?}", find_winner(inp));
}
return;
}
fn find_winner(mut n: u64) -> String{
let mut win = 0;
while n>1{
if n.is_power_of_two(){
n /= 2;
}
else{
n -= n.next_power_of_two()/2;
}
win += 1;
}
let winner =
if win % 2 == 0{
String::from("Richard")
} else{
String::from("Louise")
};
winner
}
fn read_one_line() -> String{
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed to read");
input
}
Your inner loop can be replaced by a combination of builtin functions:
let win = if n > 0 {
n.count_ones() + n.trailing_zeros() - 1
} else {
0
};
Also, instead of allocating a string every time find_winner is called,
a string slice may be returned:
fn find_winner(n: u64) -> &'static str {
let win = if n > 0 {
n.count_ones() + n.trailing_zeros() - 1
} else {
0
};
if win % 2 == 0 {
"Richard"
} else{
"Louise"
}
}
Avoiding memory allocation can help speeding up the application.
At the moment, the read_one_line function is doing one memory allocation per call, which can be avoided if you supply the String as a &mut parameter:
fn read_one_line(input: &mut String) -> &str {
io::stdin().read_line(input).expect("Failed to read");
input
}
Note how I also alter the return type to return a slice (which borrows input): further uses here do not need to modify the original string.
Another improvement is I/O. Rust is all about explicitness, and it means that io::stdin() is raw I/O: each call to read_line triggers interactions with the kernel.
You can (and should) instead used buffered I/O with std::io::BufReader. Build it once, then pass it as an argument:
fn read_one_line<'a, R>(reader: &mut R, input: &'a mut String) -> &'a str
where R: io::BufRead
{
reader.read_line(input).expect("Failed to read");
input
}
Note:
it's easier to make it generic (R) than to specify the exact type of BufReader :)
annotating the lifetime is mandatory because the return type could borrow either parameter
Putting it altogether:
fn read_one_line<'a, R>(reader: &mut R, input: &'a mut String) -> &'a str
where R: io::BufRead
{
reader.read_line(input).expect("Failed to read");
input
}
fn main() {
let mut reader = io::BufReader::new(io::stdin());
let mut input = String::new();
let n: usize = read_one_line(&mut reader, &mut input).
trim().parse().unwrap();
for _i in 0..n{
let inp: u64 = read_one_line(&mut reader, &mut input).
trim().parse().unwrap();
println!("{:?}", find_winner(inp));
}
return;
}
with the bigger win probably being I/O (might even be sufficient in itself).
Don't forget to also apply #John's advices, this way you'll be allocation-free in your main loop!

simple algorithm with scala

Very simple algorithm in scala
def listReplication(num: Int, arr: List[Int]): List[Int] = {
val l = new ListBuffer[Int]()
for (a <- arr.indices) {
for (b <- 1 to num) {
l += arr.apply(a)
}
}
l.toList
}
Can it writes in immutable ?
Cannot use recursion
Thanks
Cat skinning one-liner
def listReplication(num: Int, arr: List[Int]):List[Int] =
arr.flatMap(a=>List.fill(num)(a))
You can use the for { ... } yield syntax to traverse any collection (or Cartesian product of collections) and produce a new collection, with no mutable data:
def listReplication(num: Int, arr: List[Int]): List[Int] = {
for {
a <- arr
b <- 1 to num
} yield a
}

How can I turn a string into an operator?

Is there a way to convert a string (e.g. "+", "-", "/", "*") into their respective math operators (+, -, /, *)?
In Python you can do:
import operator
ops = {"+": operator.add, "-": operator.sub} # etc.
print ops["+"](1,1) # prints 2
Is there a similar library or method for Go?
You can do this with function values:
ops := map[string]func(int, int) int{
"+": func(a, b int) int { return a + b },
"-": func(a, b int) int { return a - b },
"*": func(a, b int) int { return a * b },
"/": func(a, b int) int { return a / b },
}
fmt.Println(ops["+"](4, 2))
fmt.Println(ops["-"](4, 2))
fmt.Println(ops["*"](4, 2))
fmt.Println(ops["/"](4, 2))
Output: Go Playground
6
2
8
2
For a nice print:
a, b := 4, 2
for op, fv := range ops {
fmt.Printf("%d %s %d = %d\n", a, op, b, fv(a, b))
}
Output:
4 / 2 = 2
4 + 2 = 6
4 - 2 = 2
4 * 2 = 8
There are few options but I would recommend just constructing the problem in a switch or using a map[string]func to provide a function which does the same. So... Either this;
ops := map[string]func(int, int) int{
"+": func(a, b int) int { return a + b },
"-": func(a, b int) int { return a - b },
"*": func(a, b int) int { return a * b },
"/": func(a, b int) int { return a / b },
}
or this;
func doOp(string op, lhs, rhs int) int {
switch (op) {
case "+":
return lhs + rhs
// ect
default:
// error cause they gave an unknown op string
}
}
Which I use would probably depend on scope. The function imo is more portable. The map isn't read only so for example someone else could just hose it entirely by assigning a different method to "+".
EDIT: After thinking about it the map sucks and I'd recommend against it. The function is more clear, stable, consistent, predictable, encapsulated ect.
Here's another implementation. This is give or take 3x faster than the string-based switch implementation but readability is a little less.
func RunOp(sign string, a, b int) int {
s := byte(sign[0])
switch s {
case byte(43):
return a+b
case byte(45):
return a-b
case byte(47):
return a/b
case byte(42):
return a*b
default:
return 0
}
}

Resources