bugfix> java > 投稿

2つのリストで反復処理を実行しています。

// events and items are two lists.
Iterator<Event> eventIterator = events.iterator();
Iterator<EventItem> itemIterator = items.iterator();
while (eventIterator.hasNext()) {
    Event event = eventIterator.next();
    while (itemIterator.hasNext()) {
        EventItem item = itemIterator.next();
        if (event.getId().equals(item.getEventId())) {
            // CLAIMED
            itemIterator.remove();
        }
    }
    // PROBLEM IS HERE.
}

問題:

itemIterator をループしました最後まで、また itemIterator からアイテムを削除しましたアイテムが請求された場合。しかし、次の eventIterator の繰り返し実行します、 itemIterator すでに終わりです。

itemIterator をリセットするにはどうすればよいですか 0 を配置する items.iterator() を使用して再起動せずにそれは itemIterator から削除されたアイテムを戻すからです次の反復のため。

1つの item itemIterator から1人の event のみが要求できます eventIterator から 。そのため、要求された後にそのアイテムを繰り返し保持するのは意味がありません。したがって、 itemIterator からアイテムを削除します 。

従来のfor-eachループよりも反復回数が減る場合、私は代替案を受け入れています。

回答 2 件
  • How can I reset itemIterator   items.iterator() を使用して再開始せずに0を配置する  それは itemIterator から削除されたアイテムを戻すからです  次の反復のため。

    いいえ、できません。 itemIterator.remove()  からアイテムを削除しますコレクション イテレータだけでなく、イテレータを取得しました。そのコレクションから新しいイテレータを取得すると、そのアイテムはそのイテレータに含まれなくなります。削除しました。 JavaDocから:

    Removes from the underlying collectionthe last element returned by this iterator (optional operation). This method can be called only once per call to next()

    (私の強調)

    イテレータをリセットすることはできません。 while 内で新しいものを取得するだけです 。

    Iterator<Event> eventIterator = events.iterator();
    while (eventIterator.hasNext()) {
        Event event = eventIterator.next();
        Iterator<EventItem> itemIterator = items.iterator();
        while (itemIterator.hasNext()) {
            EventItem item = itemIterator.next();
            if (event.getId().equals(item.getEventId())) {
                // CLAIMED
                itemIterator.remove();
            }
        }
        // If you need to loop a second time for some reason:
        itemIterator = items.iterator();
        // ...
    }
    
    

  • このようなネストされたループの使用はO(N * M)であり、コストがかかりますが、達成しようとしている目的をわかりにくくする冗長なものでもあります。 Java 8のストリームを使用することをお勧めします。

    // get all the event's ids
    Set<String> eventIds = events.stream()
            .map(Event::getId)
            .collect(Collectors.toSet());
    // remove the entries from items with a matching id.
    items.removeIf(i -> eventIds.contains(i.getEventId()));
    
    

    これには、O(N + M)の時間の複雑さがあります。

    And, removed/claimed items get added to another list (I call it EventDto, data transfer object)

    最初にリストを作成することでそれを行うことができます。

    // remove the entries from items with a matching id.
    List<EventItem> toMove = items.stream()
                                  .filter(i -> eventIds.contains(i.getEventId()))
                                  .collect(Collectors.toList());
    items.removeAll(toMove);
    anotherList.addAll(toMove);
    
    

    idがマップのキーとして使用された場合、これはより効率的です。

    例えば

    Map<String, Event> events = ... // events keyed by id
    Map<String, EventItem> items = ... // event items keys by eventId
    events.keySet().removeAll(items.keySet());
    
    

あなたの答え