【问题标题】:Efficient way to get indexes of matched items using Lists使用列表获取匹配项索引的有效方法
【发布时间】:2011-08-18 12:30:36
【问题描述】:

我有两个列表 A 和 B。我想找出 A 中与 listB 的元素匹配的元素的索引。像这样的:

ArrayList listA = new ArrayList();
listA.add(1);listA.add(2);listA.add(3);listA.add(4);
ArrayList listB = new ArrayList();
listB.add(2);listB.add(4);
ArrayList listC = new ArrayList();
for(int i=0; i<listB.size();i++) {
   int element = listB.get(i);
   for(int j=0; j<listA.size(); j++) {
      if(listA.get(j) == element) listC.add(j);
   }
}

我想这是一种丑陋的做法。查找与 B 中的所有元素匹配的 A 的所有索引的最佳方法是什么?我相信 collections api 中存在一个名为 containsAll 的方法 - 不要认为它返回匹配的索引。

【问题讨论】:

标签: java collections arraylist


【解决方案1】:

如果您必须使用ArrayList,您可以从ArrayList 创建一个HashSet。这将调用contains O(1)。创建HastSet 需要 O(n)。如果您可以以HashSet 开头,那就最好了。

public static void main(String[] args) 
{
    List listA = new ArrayList();
    listA.add(1);
    listA.add(2);
    listA.add(3);
    listA.add(4);
    List listB = new ArrayList();
    listB.add(2);
    listB.add(4);
    Set hashset = new HashSet(listA);

    for(int i = 0; i < listB.size(); i++) 
    {
        if(hashset.contains(listB.get(i))) 
        {
            listC.add(i);
            System.out.println(i);
        }
    }   
}

【讨论】:

  • contains() 效率不高。
  • so.. 除了 O(n) 的最小复杂度之外,没有别的办法吗?
  • 对我来说,遍历列表 A 中的 n 个元素并遍历列表 B 中的 m 个元素对于列表 A 中的每个元素似乎比 O(n) 效率低。
  • 在创建 HashSet 时会循环遍历列表 A 中的 n 个元素?
  • @DwB - 包含一个 HashSet 是有效的,它的 O(1)
【解决方案2】:

Guava 库带有一个方法

"SetView com.google.common.collect.Sets.intersection(Set a, Set b)

这将给出两个集合中包含的元素,但不给出索引。虽然之后应该很容易获取索引。

【讨论】:

  • 第三方库就这么简单?
  • @Jay,是的,那是 Java ......我可以想象如果我在 C# 世界中为了改变而写了一个非常简单的 LINQ 行......
【解决方案3】:

简单:

List<Integer> listA = new ArrayList<Integer>();
listA.add(1);
listA.add(2);
listA.add(3);
listA.add(4);

List<Integer> listB = new ArrayList<Integer>();
listB.add(2);
listB.add(4);

List<Integer> listC = new ArrayList<Integer>();

for ( Integer item : listA ) {
    int index = listB.indexOf( item );
    if ( index >= 0 ) {
        listC.add(index);
    }
}

但这只有在没有重复的情况下才有效,如果有重复的索引,你必须按照你的方式来做,浏览完整的列表。

编辑

我以为你想要的是元素,而不是索引,集合不会给你索引,只有元素。

【讨论】:

  • 这里使用 contains() 方法的时间复杂度是多少?其次,我需要索引而不是这些索引处的实际元素。
  • 包含 是一个 O(n) 操作。
  • 这是线性复杂度。查找索引呢?
  • 更新了答案和你的问题标题,说 indexes 而不是匹配项。
【解决方案4】:

假设没有重复值,为什么不使用ArrayList.indexOf


public final class ArrayListDemo {
    public static void main(String[]args){
        findIndices(createListA(), createListB());      
    }

    private static final List<Integer> createListA(){
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(3);
        list.add(5);

        return list;
    }

    private static final List<Integer> createListB(){
        List<Integer> list = new ArrayList<Integer>();
        list.add(0);
        list.add(2);
        list.add(3);
        list.add(4);

        return list;
    }

    private static void findIndices(List<Integer> listA, List<Integer> listB){
        for(int i = 0; i < listA.size(); i++){  
            // Get index of object in list b
            int index = listB.indexOf(listA.get(i));

            // Check for match
            if(index != -1){
                System.out.println("Found match:");
                System.out.println("List A index = " + i);
                System.out.println("List B index = " + index);
            }
        }
    }
}

输出

Found match:
List A index = 1
List B index = 2

【讨论】:

  • get 以恒定时间运行(即 O(1)),indexOf 以线性时间运行(即 O(n))。
  • for 循环意味着 - 您将执行 indexOf 的次数与 A 中的元素数量一样多 - 您认为 SwDevMan81 下面的答案更有效吗?
【解决方案5】:

如果列表 A 和列表 B 以相同的顺序排序(我假设升序,但降序也可以)这个问题有一个 O(n) 的解决方案。下面是一些(非正式的、未经测试的)代码。当循环退出时,indexMap 应该包含列表 A 中与列表 B 中的元素匹配的每个元素的索引以及列表 B 中匹配元素的索引。

国际电流A; 国际电流B; int listAIndex = 0; int listBIndex = 0; Map indexMap = new HashMap(); currentA = listA.get(listAIndex); currentB = listB.get(listBIndex); while ((listAIndex currentB) { ++列表B索引; } }

【讨论】:

  • 如果列表没有排序,我猜 - 排序所涉及的额外复杂性会加起来总复杂性,不是吗?
  • 复杂度成为排序中效率最低的 vs O(n)。通常这意味着排序的复杂性。
【解决方案6】:

使用Apache CollectionUtils,有很多选择

【讨论】:

    猜你喜欢
    • 2012-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-14
    • 1970-01-01
    • 2020-03-02
    相关资源
    最近更新 更多