Is it possible to use high order functions instead of loops?


#1

Hello,

I’m new to Rust and trying to learn it by trying to solve hackerrank.com problems. One problem is displayed below. My questions is that can I make it look more beautiful using high order functions? And how would it look if high order functions are used?

#![feature(old_io)]
#![allow(deprecated)]

use std::old_io;
use std::cmp;

fn main()
{
    let mut line = old_io::stdin().read_line().ok().expect("Failed to read line.");
    let l: u16 = line.trim().parse().unwrap();
    line = old_io::stdin().read_line().ok().expect("Failed to read line.");
    let r: u16 = line.trim().parse().unwrap();

    let mut max_value: u16 = 0;

    for i in l..r + 1
    {
        for j in i..r + 1
        {
            max_value = cmp::max(max_value, i ^ j);
        }
    }

    println!("{:?}", max_value);
}

#2

Using itertools, you can do the following:

extern crate itertools;
use std::cmp;
use std::io;
use itertools::Itertools;

fn main()
{
    let mut line = String::new();
    io::stdin().read_line(&mut line).ok().expect("Failed to read line.");
    let l: u16 = line.trim().parse().unwrap();
    
    line.clear();
    io::stdin().read_line(&mut line).ok().expect("Failed to read line.");
    let r: u16 = line.trim().parse().unwrap();
    //                         Bug vvv see below
    let powers = (l..r + 1).cartesian_product(l..r + 1).map(|(i, j)| i ^ j);
    let max_value = powers.fold(0, |max_value, next| cmp::max(max_value, next));
    println!("{:?}", max_value);
}

#3

The key to solving this in a more functional style is to gain intuition for what kinds of transformation each of the options does, and then apply that to the structure of your problem. I just did this by practicing a lot, I wish there was a better way :frowning:

For example, a fold is “i have a list of things and I want to make a single thing out of it” which is the fundamental operation you’re doing here.

@stebalien has already posted a solution, so I’ll leave it at that for now :smile:


#4

Ok, thank you for your help :smile:

I cannot use libraries with Hackerrank submissions. So I cannot use cartesian_product() function to solve my problem. But it’s good to know that itertools library exists.


#5

Actually, my solution is wrong anyways. You’re not actually looking for the cartesian product (my solution uses l..r+1 in the inner for loop). You could actually do this with flat_map (and drop the itertools dependency):

let powers = (l..r+1).flat_map(|i| (i..r+1).map(move |j| i ^ j));
// Move copies i into the closure to prevent lifetime issues.

Adding on to Steve’s comment,

  • flat_map: I have an iterator of As and I want to produce iterator of Bs where each A contributes to multiple Bs but each B is derived from a single A.
  • map: I have an iterator of As and I want to produce an iterator of Bs where each A contributes to exactly one B.

#6

That’s interesting. I was trying yesterday to combine map() functions too, but I got this lifetime error:

`i` does not live long enough

So now I know also that move copies i to another closure. Very nice, thank you!


#7

This thread might be helpful (if a bit dated) http://internals.rust-lang.org/t/still-confused-by-move-vs-closures/1430/.