Как я могу получить доступ к элементам в коллекции Java за пределами моего итератора, не теряя своего места? - PullRequest
3 голосов
/ 29 января 2011

Я создал класс под названием Месяц, который расширяет Календарь, который я использую для хранения событий в течение определенного месяца. У меня есть несколько месяцев объектов Месяца, хранящихся в TreeSet. Большинство событий, которые я хочу записать, длятся в течение нескольких месяцев и указаны только по месяцу их начала (и продолжительности в месяцах). Я хочу быть в состоянии сделать это:

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, чтобы избежать дубликатов (хотя, возможно, этот наклон неправильный?)

Такое чувство, что было бы намного проще сделать это с простым старым массивом, но коллекция полезна для других частей программы. Возможно, я смогу использовать несколько итераторов и просто «использовать их» по мере необходимости для этих вылазок в течение нескольких месяцев после моего основного итератора «закладки»? Хотя не совсем элегантно. Или есть хак для того, чтобы «заглянуть» за пределы, на которые указывает мой итератор?

Я совершенно новичок во всем этом, поэтому, возможно, я просто ошибаюсь в дизайне. Все советы приветствуются!

Ответы [ 3 ]

2 голосов
/ 29 января 2011

Как выглядят объекты Event и Month?Я думаю, что у вас будет работать:

for(Event event : events) {

   for(Month aMonth : myMonths) {

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

    }
}

В качестве альтернативы вы можете перевернуть его и пойти другим путем, сделать свой внешний итератор Months, а свой внутренний итератор Events.Это тоже должно работать, условие if (), вероятно, будет таким же.

1 голос
/ 29 января 2011

В зависимости от того, сколько событий и месяцев вы имеете дело за один раз, наивный подход может быть лучшим.Я бы начал с того, что позволил вашим циклам for обрабатывать итераторы и принял тот факт, что вы будете выполнять (m * n) итераций.Затем, если вы обнаружите, что это место вызывает значительное замедление, вы можете попробовать несколько других методов, чтобы ускорить процесс, не делая ваш код слишком сложным.

Попытка поиска вперед и назад сделает ваш код трудным для понимания и более подверженным ошибкам, не обязательно принося вам много пользы с точки зрения производительности.Обычно вы не заметите существенной разницы в производительности, пока не расскажете не менее чем о сотнях элементов в обеих коллекциях (в этом случае вы можете начать с чего-то простого, например, разбить данные на годы, например, чтобы уменьшить накладные расходыдвойных вложенных for петель).

Редактировать

Однако, поскольку я просто не могу с собой поделать, вот полус элегантная стратегия, которая потребуетПреимущество того факта, что ваши события и месяцы хранятся в порядке возрастания (я предполагаю, что события хранятся в порядке их даты начала).Он использует 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 голосов
/ 30 января 2011

В библиотеке гуавы Google есть PeekingIterator, которая допускает одноэлементную заглядывание. Создайте его с помощью Iterators.peekingIterator(Iterator).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...