Skip to content

Instantly share code, notes, and snippets.

@darklinden
Created April 24, 2024 01:55
Show Gist options
  • Save darklinden/cbedab7603ef369d7d5075eb731db058 to your computer and use it in GitHub Desktop.
Save darklinden/cbedab7603ef369d7d5075eb731db058 to your computer and use it in GitHub Desktop.
Is there a better algorithm for grouping projects by activity timeframe?
use std::collections::{HashMap, HashSet};
#[derive(Clone, Debug)]
struct Item {
start: i64,
end: i64,
id: i32,
}
impl Item {
fn new(start: i64, end: i64, id: i32) -> Self {
Self { start, end, id }
}
}
fn get_groups_active(items: Vec<Item>) -> Vec<((i64, i64), Vec<i32>)> {
// all the time points
let mut time_points: HashSet<i64> = HashSet::new();
// items group by the start time
let mut start_groups: HashMap<i64, Vec<i32>> = HashMap::new();
// items group by the end time
let mut end_groups: HashMap<i64, Vec<i32>> = HashMap::new();
// Iterate over each item
for item in items {
time_points.insert(item.start);
time_points.insert(item.end);
// Add the item's ID to the start time group
start_groups.entry(item.start).or_default().push(item.id);
// Add the item's ID to the end time group
end_groups.entry(item.end).or_default().push(item.id);
}
let mut time_points = time_points.into_iter().collect::<Vec<_>>();
time_points.sort();
let mut time_start = -1;
let mut time_end;
let mut active_items = HashSet::new();
let mut active_groups = Vec::new();
for time in time_points {
let old_active_items = active_items.clone();
let mut has_changed = false;
// Remove items that have ended
if let Some(ended_items) = end_groups.get(&time) {
for item in ended_items {
active_items.remove(item);
}
has_changed = true;
}
// Add items that have started
if let Some(started_items) = start_groups.get(&time) {
for item in started_items {
active_items.insert(*item);
}
has_changed = true;
}
if has_changed {
if !old_active_items.is_empty() {
time_end = time;
active_groups.push((
(time_start, time_end),
old_active_items.iter().cloned().collect(),
));
}
time_start = time;
}
}
active_groups
}
fn get_active_items_by_time(data: &[((i64, i64), Vec<i32>)], time: i64) -> Option<Vec<i32>> {
data.binary_search_by(|(time_range, _)| {
if time < time_range.0 {
std::cmp::Ordering::Greater
} else if time >= time_range.1 {
std::cmp::Ordering::Less
} else {
std::cmp::Ordering::Equal
}
})
.ok()
.map(|idx| data[idx].1.clone())
}
fn main() {
let items = vec![
Item::new(0, 50, 0),
Item::new(0, 100, 1),
Item::new(0, 25, 2),
Item::new(0, 40, 3),
Item::new(20, 40, 4),
Item::new(60, 98, 5),
// Add more items here...
];
let active_groups = get_groups_active(items);
for (group, ids) in &active_groups {
println!("[{},{}) => {:?}", group.0, group.1, ids);
}
for time in 0..100 {
let active_items = get_active_items_by_time(&active_groups, time);
println!("{} => {:?}", time, active_items);
}
}
// Output:
// [0,20) => [0, 2, 1, 3]
// [20,25) => [0, 2, 1, 3, 4]
// [25,40) => [0, 1, 3, 4]
// [40,50) => [0, 1]
// [50,60) => [1]
// [60,98) => [1, 5]
// [98,100) => [1]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment