use crate::online::first_fit::__internal_first_fit;
use crate::wrapper::SizedWrapper;
use crate::{Bin, Pack};
pub fn first_fit_decreasing<T>(bin_size: usize, mut items: Vec<T>) -> Vec<Bin<T>>
where
T: Pack,
{
assert!(bin_size > 0, "Bin size must be greater than 0");
items.sort_unstable_by(|a, b| b.size().cmp(&a.size()));
let lower_bound: usize = ((items.iter().map(|item| item.size()).sum::<usize>() as f64)
/ (bin_size as f64))
.ceil() as usize;
__internal_first_fit(bin_size, items, lower_bound)
}
pub fn first_fit_decreasing_by_key<T, SizeFunc>(
bin_size: usize,
items: Vec<T>,
key_func: SizeFunc,
) -> Vec<Bin<T>>
where
SizeFunc: Fn(&T) -> usize + Clone,
{
assert!(bin_size > 0, "Bin size must be greater than 0");
let mut items: Vec<_> = items
.into_iter()
.map(|item| SizedWrapper::new(key_func.clone(), item))
.collect();
items.sort_unstable_by(|a, b| b.size().cmp(&a.size()));
let lower_bound: usize = ((items.iter().map(|item| item.size()).sum::<usize>() as f64)
/ (bin_size as f64))
.ceil() as usize;
__internal_first_fit(bin_size, items, lower_bound)
.into_iter()
.map(|bin| bin.map(|item| item.take()))
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tests::{generate_test_bins, generate_test_set_a};
#[test]
fn it_works() {
let (test_data, bin_size) = generate_test_set_a();
let result = first_fit_decreasing(bin_size, test_data);
let expected = generate_test_bins(
20,
vec![
vec![19, 1], vec![19, 1], vec![10, 10], vec![10, 4, 3, 1, 1], ],
);
assert_eq!(expected, result)
}
#[test]
fn it_works_by_key() {
let (test_data, bin_size) = generate_test_set_a();
let test_data = test_data
.into_iter()
.map(|item| item.make_unpacked())
.collect::<Vec<_>>();
let result = first_fit_decreasing_by_key(bin_size, test_data, |item| item.size);
let expected: Vec<_> = generate_test_bins(
20,
vec![
vec![19, 1], vec![19, 1], vec![10, 10], vec![10, 4, 3, 1, 1], ],
)
.into_iter()
.map(|bin| bin.map(|item| item.make_unpacked()))
.collect();
assert_eq!(expected, result)
}
}