【问题标题】:Removing objects from list based on Id match from other list根据其他列表中的 Id 匹配从列表中删除对象
【发布时间】:2014-04-04 14:18:31
【问题描述】:

我有一个对象列表List<A> list1... A 有两个成员 idname... 现在我还有一个列表 List<Integer> list2 只包含 id。 ..我需要从list1 中删除所有A 对象,其ID 不存在于list2 中。

到目前为止我所尝试的:

void removeUnwanted(List<A> a, List<Integer> b) {
    for (A object : a) {
        if (!(b.contains(object.id))) {
            b.remove(object)
        }
    }
}

任何人都可以帮助我建议最有效的方法吗??

【问题讨论】:

标签: java algorithm collections arraylist


【解决方案1】:

您应该将 id 添加到集合中以便快速搜索,然后遍历列表并删除不在 id 集合中的 id:

Set<Integer> ids = new HashSet<Integer>(list2);
Iterator<A> it = list1.iterator();
while (it.hasNext()) {
    if (!ids.contains(it.next().id)) {
        it.remove();
    }
}

【讨论】:

    【解决方案2】:

    使用流 (Java8) 可以编写:

    List<Obj>     objects = new LinkedList<>();
    List<Integer> ids     = new LinkedList<>();
    
    // fill objects and ids
    
    Set<Integer>  idHash  = new HashSet<>(ids);
    
    objects = new LinkedList<>(objects.stream()
                                          .filter(e -> idHash.contains(e.getID()))
                                          .collect(Collectors.toList()));
    

    【讨论】:

    • 虽然肯定是 1-liner,但对我来说似乎 O(n^2),因为 contains() 是 O(n),并且是按元素完成的。远非“最高效”。
    • @amit 如果将 ID 存储在哈希集中会更快吗?
    • 一个 HashSet 提供 O(1) (平均) contains()
    【解决方案3】:

    可以在O(n)时间(平均情况)和空间中通过创建一个HashMap&lt;Integer,A&gt;来完成,其中键是ID,值是A对象。

    现在,迭代列表 list2 并仅生成键与 list2 中的某个 id 匹配的值(A 对象)。

    类java伪代码:

    Map<Integer,A> map = new HashMap<>();
    for (A a : list1) map.put(a.id,a);
    for (int id : list2) { 
       A a = map.get(id);
       //do something with a, maybe populate a new list
    }
    

    另一种方法是对两个列表进行排序,并并行迭代,同时丢弃没有匹配 id 的元素。这给出了 O(nlogn) 时间(最坏情况)和 O(1) 空间:

    高级伪代码:

    sort(list1) //according to id
    sort(list2)
    iter1 = 0
    iter2 = 0
    while (iter1<list1.size() && iter2<list2.size()) { 
       int id = list1.get(iter1).id
       if (id < list2.get(iter2)) { //discard and advance the smaller one
           list1.remove(iter1) //can be done efficiently if the list is linked list
    
       } else if (id == list2.get(iter2)) { //advance both, element should remain in list1
          iter1++; iter2++;
       } else { //advance iter2
          iter2++;
       }
    }
    

    【讨论】:

      【解决方案4】:
      public void removeUnwanted(List<A> a, List<Integer> b) {
          boolean result = false;
          for (A object : a) {
              for (int i : b) {
                  if ((i == (object.id))) {
                      result = true;
                  }
              }
              if (result == false) {
                  a.remove(object);
              }
              result = false;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2022-01-16
        • 1970-01-01
        • 1970-01-01
        • 2016-09-13
        • 1970-01-01
        • 1970-01-01
        • 2014-06-18
        • 2017-07-10
        • 1970-01-01
        相关资源
        最近更新 更多