Created
April 24, 2024 01:55
-
-
Save darklinden/cbedab7603ef369d7d5075eb731db058 to your computer and use it in GitHub Desktop.
Is there a better algorithm for grouping projects by activity timeframe?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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