2011-01-29 3 views
3

Calendarを拡張するMonthというクラスを作成しました。これは、指定した月のイベントを保持するために使用しています。私はTreeSetに格納された月オブジェクトの数年分を持っています。私が記録したいイベントのほとんどは、数ヶ月間続けられ、開始月(および期間、月)によってのみ指定されます。私はこれを行うことができます:「自分の場所を失うことなく」イテレータ以外のJavaコレクションの要素にアクセスするにはどうすればよいですか?

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ループの代わりにイテレータを使用してみましたが、イテレータを使用して次のx月にeを追加する開始日が見つかったときに別のループが発生しましたが、イテレータを開始位置に戻すことができませんでした。 ListIteratorにはprevious()メソッドがあるようですが、重複を避けるためにListではなくSortedSetを使用したいと考えています(おそらくこの傾きは間違っています)。

これははるかに簡単ですプレーンな古い配列でこれを行いますが、コレクションはプログラムの他の部分にも役立ちます。 おそらく私は複数のイテレーターを使用して、私の主要な "ブックマーク"イテレーターのすぐ後ろの数ヶ月間に、これらの接待のために必要に応じて "使用する"ことができますか?しかし、まさにエレガントに見えません。 イテレータが実際に指し示しているところを超えて "覗く"ためのハックがありますか?

私はこれには全く新しいので、設計上の誤りがあるかもしれません。すべてのアドバイスが歓迎されました!

答えて

1

一度に処理するイベントと月の数によっては、素朴なアプローチが最適かもしれません。私はあなたのforループにイテレータを処理させ、(m * n)回繰り返すという事実を受け入れることから始めます。次に、このスポットが大幅に減速していることが判明した場合は、コードを過度に複雑にすることなく、スピードアップするためのいくつかの他のテクニックを試すことができます。

前と後ろを追求しようとすると、コードを理解しにくくなり、バグが発生しやすくなります。必ずしもパフォーマンスが向上するとは限りません。通常、両方のコレクションで少なくとも数百のアイテムについて話すまでは、パフォーマンスの重要な違いに気付かないでしょう(その場合、オーバーヘッドを減らすために、データを数年に分割するなどの簡単な作業から始めればよい)ダブルネストされたforループのうちの1つ)。

しかし、私はちょうど自分自身を助けることができないので、

編集は、ここで私は(あなたのイベントと月の両方が昇順に格納されているという事実を利用します半エレガントな戦略ですイベントが開始日の順に格納されていると仮定します)。 LinkedList(リストの前後に要素を追加したり削除したりするのに非常に効率的です)を使用して、現在のイベントがどの月にまたがるかを追跡し、イベントが発生しない月が見つかるとすぐに中断します。 tは、次のとおりです

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()); 
    } 
} 

繰り返しますが、あなたはこれがどのようにはるかに複雑見ることができます:それは私はこのロジックにバグを導入し、私は徹底的なユニットテストなしで生産でこれを使用して快適に感じていないだろう可能性が高いです。一般的には、最適化すべき魅力的な理由があるまで、単純に保つ方がずっと優れています。

+0

ありがとうStriplingWarrior - 詳細な返信に感謝します。私はまだそれについて手を振っていますが、あなたの提案は確かに私に考えのための食糧を与えました! – pocketdora

2

イベントと月のオブジェクトはどのように見えますか?私は何を持っていたが機能すると思います:

for(Event event : events) { 

    for(Month aMonth : myMonths) { 

     if(aMonth >= event.startMonth && aMonth <= event.startMonth+event.duration) { 
     aMonth.add(event); 
     } 

    } 
} 

また、あなたがそれを周りに反転し、他の道を行く、あなたの外側のイテレータ月とあなたの内部イテレータのイベントを作ることができます。それもうまくいくはずですが、if()条件はおそらく同じです。

+0

ありがとうございます。ニコラス。私はすぐに両方の条件をテストするような簡単なことは考えていませんでした。 (私は多くのことを学ぶ必要があります)あなたの答えは明確かつ簡潔であり、私が問題を解決するのを助けました。 – pocketdora

関連する問題