【问题标题】:Iteration is quit after first iteration第一次迭代后退出迭代
【发布时间】:2016-04-13 13:57:17
【问题描述】:

我正在尝试比较两个不同的列表并删除重复项。但是,这两个列表有两种不同的对象类型,唯一的共同属性是应用名称。

这是代码,

public List<TvAppsType> getAvailableAppsTypesByCompanyIdSecond(int comapnyId) {
    // put apps to the model that belong to the given company id
    TVAppService tvAppService = new TVAppService();
    List<ThreatviewApp> apps = new CopyOnWriteArrayList<ThreatviewApp>();
    apps = tvAppService.getAllAppsforCompanyId(comapnyId);

    // get list of app types
    TvAppTypeService types = new TvAppTypeService();
    List<TvAppsType> apptypes = new CopyOnWriteArrayList<TvAppsType>();
    apptypes = types.getAppTypes();
    // add the items to collection for removing
    for(TvAppsType app : apptypes){
        System.out.println("-----------------------");
        System.out.println("app : " + app.getAppType_name());
    }

    Iterator<TvAppsType> itertypes = apptypes.iterator();
    Iterator<ThreatviewApp> it = apps.iterator();
    while (itertypes.hasNext()) {
        TvAppsType apptype = itertypes.next();
        while (it.hasNext()) {
            ThreatviewApp tvapp = it.next();
            if (tvapp.getApp_name().trim().equals(apptype.getAppType_name().trim())) {
                itertypes.remove();
            }
        }
    }

    for(TvAppsType app : apptypes){
        System.out.println("-----------------------");
        System.out.println("app : " + app.getAppType_name());
    }

    return apptypes;
}

问题是这仅在第一次迭代中有效,我怀疑在修改列表后,迭代行为未指定。

void remove() 从底层集合中移除最后一个元素 由此迭代器返回(可选操作)。这种方法可以 每次调用 next() 时只调用一次。迭代器的行为是 未指定是否修改了基础集合,而 除了调用此方法之外,迭代正在以任何方式进行。

当我尝试修改列表运行时时,我使用了CopyOnWriteArrayList 基本上我关注了这篇文章article

为什么迭代在第一个之后停止?如何解决此问题并删除所有重复项?

【问题讨论】:

  • 将两个列表映射到HashMap&lt;String,Object&gt; 可能更有效。之后,地图的值列表将不包含重复项(并且可以通过检查类来分隔)。插入 Map 的顺序决定了最好保留哪个列表。 (这是 O(m+n) 对 O(m*n)。)

标签: java collections


【解决方案1】:

如果您希望在apps 列表上多次迭代,则必须重置内部循环的迭代器。否则,内部 while 循环将仅遍历 apps 列表一次,之后 it.hasNext() 将为 false。

Iterator<TvAppsType> itertypes = apptypes.iterator();
while (itertypes.hasNext()) {
    TvAppsType apptype = itertypes.next();
    Iterator<ThreatviewApp> it = apps.iterator(); // the inner iterator must be
                                                  // initialized in each iteration
                                                  // of the outer loop
    while (it.hasNext()) {
        ...

【讨论】:

  • 感谢您的回答,但我们修改了 Iterator&lt;TvAppsType&gt; itertypes = apptypes.iterator(); 。所以我们不需要重置这个迭代器吗?
  • @mankadanka 您只在apptypes 上迭代一次,因此您不必重置该迭代器。您只需要确保您不会多次尝试删除相同的元素(如cybersam所述)。
【解决方案2】:

除了@Eran 的回答,你还有一个问题。一旦你删除了TvAppsType(在内部的while循环中),你不应该再次尝试删除同一个对象。此外,尽快退出内部循环将加快您的算法速度。

所以,内部循环应该是这样的:

    while (it.hasNext()) {
        ThreatviewApp tvapp = it.next();
        if (tvapp.getApp_name().trim().equals(apptype.getAppType_name().trim())) {
            itertypes.remove();
            break;
        }
    }

【讨论】:

  • 这不是一个完整的解决方案——它是对@Erin 答案的改进。
猜你喜欢
  • 1970-01-01
  • 2021-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-15
  • 2020-07-01
  • 1970-01-01
  • 2018-06-21
相关资源
最近更新 更多