I subscribe to a wonderful newsletter that, among other things, presents readers with a coding challenge every week.
Here’s this week’s question:
Given an array of people objects (where each person has a name and a number of pizza slices they’re hungry for) and a number for the number of slices that the pizza can be sliced into, return the number of pizzas you need to buy.
Example:
arr = [{ name: Joe, num: 9 }, { name: Cami, num: 3 }, { name: Cassidy, num: 4 }]
gimmePizza(arr, 8)
2 // 16 slices needed, pizzas can be sliced into 8 pieces, so 2 pizzas should be ordered
Since Rust is basically the only language I write these days (even though I write it poorly), I naturally decided to use Rust.
Here was my first attempt:
#![allow(dead_code)]
struct Person<'a> {
name: &'a str,
slices_requested: usize,
}
fn main() {
let persons: Vec<Person> = vec![
Person {
name: "Joe",
slices_requested: 9,
},
Person {
name: "Cami",
slices_requested: 3,
},
Person {
name: "Cassidy",
slices_requested: 4,
},
];
assert_eq!(gimme_pizza(&persons, 8), 2);
println!("Need to order {} pizzas", gimme_pizza(&persons, 8));
}
fn gimme_pizza(persons: &[Person], slices_per_pizza: usize) -> usize {
let mut slices_needed = 0;
for person in persons {
slices_needed += person.slices_requested;
}
if slices_needed % slices_per_pizza == 0 {
slices_needed / slices_per_pizza
} else {
slices_needed / slices_per_pizza + 1
}
}
It works fine, but those first 4 lines of the gimme_pizza
function bugged me – I shouldn’t have to declare a mutable variable and set it to 0 like that. I knew there was a better way, probably using map
, to make that summation a bit tighter, but I couldn’t figure out how to get it to work.
Thanks to some help from the Fediverse, I now know this is what I was reaching for:
fn gimme_pizza_using_map(persons: &[Person], slices_per_pizza: usize) -> usize {
let slices_needed: usize = persons.iter().map(|person| person.slices_requested).sum();
if slices_needed % slices_per_pizza == 0 {
slices_needed / slices_per_pizza
} else {
slices_needed / slices_per_pizza + 1
}
}
Alternatively, I could have used fold
, another pair of Fediverse users pointed out. That would have looked like this:
fn gimme_pizza_using_fold(persons: &[Person], slices_per_pizza: usize) -> usize {
let slices_needed: usize = persons.iter().fold(0, |running_sum, person| {
running_sum + person.slices_requested
});
if slices_needed % slices_per_pizza == 0 {
slices_needed / slices_per_pizza
} else {
slices_needed / slices_per_pizza + 1
}
}
I’m not sure with I prefer… I’m guessing fold
is more versatile for cases where you want to do more than summing. And I don’t love that map returns its own object type that you can only do certain things with, whereas fold is more an all-in-one approach.
Separately, I’m curious if there’s a more concise way to go from slices_needed
to pizzas_needed
, besides my big ole, 5-line if/else using modulo.