想象一下,我们已经对时间间隔列表进行了排序(按开始时间排序)。 我正在寻找项目的最佳解决方案'这些区间到轴,结果是一组对象,描述:投影间隔开始和结束时间以及落入投影间隔的源区间数组。
让我举例解释一下:假设我们有4个区间作为输入(按开始时间排序,然后按结束时间排序):
[---R1---)
[-----R2-----)
[---------R3-------)
[----R4----)
--|-----|--|----|----|-----|---> t (time axis)
1 3 2 3 2
在这种情况下,我希望获得5个元素的数组,每个元素都是一个描述间隔开始/结束的对象和一个源间隔列表。图表上的轴下方的数字显示该列表中的项目数。
请帮助我找到解决此任务的最快方法
答案 0 :(得分:1)
这样的东西?
def groupIntervals(intervals):
events = {}
for start, stop, name in intervals:
if start not in events: events[start] = []
events[start].append(('start', name))
if stop not in events: events[stop] = []
events[stop].append(('stop', name))
last = None
output = []
active = set()
for time in sorted(events.keys()):
if active and last is not None:
output.append((last, time, active.copy()))
last = time
for action, name in events[time]:
if action == 'start': active.add(name)
elif action == 'stop': active.remove(name)
else: assert False
return output
使用示例:
>>> groupIntervals([(1, 3, 'R1'), (2, 5, 'R2'), (2, 6, 'R3'),
... (4, 6, 'R4')])
[(1, 2, set(['R1'])),
(2, 3, set(['R1', 'R2', 'R3'])),
(3, 4, set(['R2', 'R3'])),
(4, 5, set(['R4', 'R2', 'R3'])),
(5, 6, set(['R4', 'R3']))]
C ++版本,使用更清晰的数据结构。
#include <cstdio>
#include <limits>
#include <list>
#include <queue>
#include <string>
#include <vector>
struct Interval {
Interval(std::string name, int start, int stop);
std::string name;
int start;
int stop;
};
Interval::Interval(std::string name, int start, int stop)
: name(name), start(start), stop(stop) {
}
typedef std::list<std::vector<Interval>::const_iterator> ActiveList;
struct StopEvent {
StopEvent(int stop, ActiveList::iterator j);
int stop;
ActiveList::iterator j;
};
StopEvent::StopEvent(int stop, ActiveList::iterator j)
: stop(stop), j(j) {
}
struct StopEventGreater {
bool operator()(StopEvent const& a,
StopEvent const& b) const;
};
bool StopEventGreater::operator()(StopEvent const& a,
StopEvent const& b) const {
return a.stop > b.stop;
}
void Sweep(std::vector<Interval> const& intervals) {
std::vector<Interval>::const_iterator i(intervals.begin());
std::priority_queue<StopEvent,
std::vector<StopEvent>,
StopEventGreater> active_queue;
ActiveList active_list;
int last_time(std::numeric_limits<int>::min());
while (i != intervals.end() || !active_queue.empty()) {
bool start(i != intervals.end() &&
(active_queue.empty() || i->start < active_queue.top().stop));
int time(start ? i->start : active_queue.top().stop);
if (time != last_time && !active_list.empty()) {
std::printf("[%d, %d):", last_time, time);
for (ActiveList::const_iterator j(active_list.begin());
j != active_list.end();
++j) {
std::printf(" %s", (*j)->name.c_str());
}
std::putchar('\n');
}
last_time = time;
if (start) {
active_queue.push(StopEvent(i->stop,
active_list.insert(active_list.end(), i)));
++i;
} else {
active_list.erase(active_queue.top().j);
active_queue.pop();
}
}
}
int main(void) {
std::vector<Interval> intervals;
intervals.push_back(Interval("R1", 0, 4));
intervals.push_back(Interval("R2", 1, 9));
intervals.push_back(Interval("R3", 1, 11));
intervals.push_back(Interval("R4", 6, 11));
Sweep(intervals);
}
答案 1 :(得分:0)
最后我找到了最有效的方法。它使用一个排序操作和O(N * 2)次迭代来构建结果。
public IEnumerable<DateProjectedItems<T>> Project(IList<T> items)
{
if (items.Count <= 1)
{
if (items.Count == 0)
{
yield break;
}
yield return new DateProjectedItems<T>
{
DateRange = items[0].DateRange,
Items = items
};
}
else
{
var endOrdered = items.OrderBy(i => i.DateRange.DateTimeTo).ToList();
var active = new List<T>();
DateTime? last = null;
foreach (var pair in TwoArrayIterator(items, endOrdered))
{
DateTime current = pair.Key == 1 ? pair.Value.DateRange.DateTimeFrom : pair.Value.DateRange.DateTimeTo;
if (last != null && current != last)
{
yield return new DateProjectedItems<T>
{
DateRange = new DateRange(last.Value, current),
Items = active.ToList()
};
}
if (pair.Key == 1)
{
active.Add(pair.Value);
}
else
{
active.Remove(pair.Value);
}
last = current;
}
}
}
public IEnumerable<KeyValuePair<int, T>> TwoArrayIterator(IList<T> arr1, IList<T> arr2)
{
var index1 = 0;
var index2 = 0;
while (index1 < arr1.Count || index2 < arr2.Count)
{
if (index1 >= arr1.Count)
yield return new KeyValuePair<int, T>(2, arr2[index2++]);
else if (index2 >= arr2.Count)
yield return new KeyValuePair<int, T>(1, arr1[index1++]);
else
{
var elt1 = arr1[index1];
var elt2 = arr2[index2];
if (elt1.DateRange.DateTimeFrom < elt2.DateRange.DateTimeTo)
{
index1++;
yield return new KeyValuePair<int, T>(1, elt1);
}
else
{
index2++;
yield return new KeyValuePair<int, T>(2, elt2);
}
}
}
}