我创建了一个名为Month的类,它扩展了Calendar,我用它来保存给定月份的事件。我有几年存储在TreeSet中的Month对象。我想记录的大多数事件持续数月,并且仅由其开始月份(以及持续时间,以月为单位)指定。我希望能够做到这一点:
for ( Event e : events )
{
for ( Month aMonth : myMonths )
{
// check if this is a start month for e
// if it is, call aMonth.addEvent(e);
// and also add e to the next e.getDuration() months of myMonths
// and then start checking again from the month where we called addEvent(e)
// in case there is another occurrence of e starting
// before the first one has finished
}
}
这是我遇到麻烦的首都。我尝试使用迭代器而不是foreach循环,并且在找到使用迭代器将e添加到下一个x月的开始日期时使用单独的循环,但是我无法将迭代器返回到它开始的位置。看起来ListIterator有一个previous()方法,但是我想使用SortedSet而不是List,以确保避免重复(尽管这种倾向可能是错误的?)
使用普通的旧数组执行此操作会感觉更容易,但该集合对程序的其他部分非常有用。 也许我可以使用多个迭代器,并根据需要将它们“用起来”,直到我主要的“书签”迭代器之后的几个月?虽然看起来并不优雅。 或者是否有“偷看”超出我的迭代器实际指向的位置?
我对这一切都很陌生,所以我可能只是犯了一个设计错误。欢迎所有建议!
答案 0 :(得分:2)
Event和Month对象是什么样的?我认为你的工作会起作用:
for(Event event : events) {
for(Month aMonth : myMonths) {
if(aMonth >= event.startMonth && aMonth <= event.startMonth+event.duration) {
aMonth.add(event);
}
}
}
或者你可以翻转它并转向其他方式,使你的外部迭代器成为月份,你的内部迭代器成为事件。这应该也可以,if()条件可能是相同的。
答案 1 :(得分:1)
根据您一次处理的事件数和月数,天真的方法可能是最好的。我首先让你的for
循环处理迭代器,并接受你将进行(m * n)次迭代的事实。然后,如果您发现此位置导致显着减速,您可以尝试其他一些技术来加快速度,而不会使代码过于复杂。
尝试前进和后退将使您的代码难以理解并且更容易出错,而不必在性能方面获得更多。通常你不会注意到性能上的显着差异,直到你在两个集合中谈论至少数百个项目(在这种情况下,你可以从简单的事情开始,比如将数据分解成数年,例如,减少开销双嵌套for
循环)。
修改强>
然而,由于我无法自拔,这是一个半优雅的策略,它将利用你的事件和月份都按升序存储的事实(我假设事件按照他们的顺序存储开始日期)。它使用LinkedList(在列表的前面和后面添加和删除元素非常有效)来跟踪当前事件可能跨越的月份,然后在找到事件没有的月份后立即中断。包括:
LinkedList<Month> monthList = new LinkedList<Month>();
var i = monthList.getIterator();
for(Event ev : events)
{
shiftList(monthList, i, ev);
for(Month m : monthList)
{
if (!isInMonth(ev, m)) break;
m.addEvent(ev);
}
}
...
// Remove months that are not in scope from the front of the list.
// Add months that are in scope to the end of the list
public void shiftList(LinkedList<Month> monthList, Iterator<Month> i, Event ev)
{
while(!monthList.size() > 0 && !isInMonth(ev, monthList.getFirst()))
{
monthList.removeFirst();
}
while(i.hasNext() && isInMonth(ev, monthList.getLast()))
{
monthList.addLast(i.next());
}
}
同样,你可以看到它有多复杂:我很可能在这个逻辑上引入了一个错误,如果没有彻底的单元测试,我会觉得在生产中使用它是不舒服的。在你有一个令人信服的理由进行优化之前,你通常要保持简单。
答案 2 :(得分:0)
Google的guava库提供了PeekingIterator
,允许使用单元素的peekahead。通过Iterators.peekingIterator(Iterator)
创建一个。