【问题标题】:Count the occurrences of items in ArrayList计算 ArrayList 中项目的出现次数
【发布时间】:2011-02-08 11:41:31
【问题描述】:

我有一个java.util.ArrayList<Item> 和一个Item 对象。

现在,我想获取Item 存储在arraylist 中的次数。

我知道我可以进行arrayList.contains() 检查,但无论它是否包含一个或多个Items,它都会返回true。

第一季度。如何找到项目在列表中存储的次数?

第二季度。另外,如果列表包含多个项目,那么我如何确定其他项目的索引,因为arrayList.indexOf(item)每次都只返回第一个项目的索引?

【问题讨论】:

  • 项目是否覆盖等于和哈希码?他们需要。
  • 为什么不扩展 ArrayList 类来添加您需要的附加功能?这就是 OOP 存在的原因;) Q1 可以通过为列表中的每个唯一项目实现一个计数器并在每次添加已经存在的项目时递增它来轻松完成。

标签: java list arraylist


【解决方案1】:

这很容易手工完成。

public int countNumberEqual(ArrayList<Item> itemList, Item itemToCheck) {
    int count = 0;
    for (Item i : itemList) {
        if (i.equals(itemToCheck)) {
          count++;
        }
    }
    return count;
}

请记住,如果您不在 Item 类中覆盖 equals,此方法将使用对象标识(因为这是 Object.equals() 的实现)。

编辑:关于您的第二个问题(请尽量将帖子限制为一个问题),您也可以手动完成。

public List<Integer> indices(ArrayList<Item> items, Item itemToCheck) {
    ArrayList<Integer> ret = new ArrayList<Integer>();
    for (int i = 0; i < items.size(); i++) {
        if (items.get(i).equals(itemToCheck)) {
            ret.add(i);
        }
    }
    return ret;
}

【讨论】:

  • 有没有其他更有效的方法,因为我的列表包含数千个项目,一个特定项目最多可以复制 4 或 5 次。所以我认为不值得比较这数千个项目来找到那 4 或 5 个重复项。请不要建议我使用 Set,因为在我的情况下不使用 Set 有充分的理由。
  • 想一想这样一个事实,即要计算项目,您需要无论如何都要遍历整个列表,因为您必须检查所有项目才能知道确切的计数。
  • 如果你想要一些时间复杂度较低的东西,那你就不走运了——你对 List 的内容一无所知,你必须检查每个位置。一种优化是将您的项目的hashCode 与列表中每个项目的hashCode 进行比较,但如果它们相等,那么您仍然必须使用equals() 检查是否相等,因为您的哈希函数可能有冲突。如果您只检查对象身份,则无需这样做,因为equals 将比较内存地址或类似的东西。
  • 如果这是必须经常做的事情,而且花费的时间会消耗性能,那么简单的 List 结构是不适合使用的。根据您要执行的操作,也许您可​​以修改 Item 以包含计数,然后添加对项目的搜索并增加计数。或者创建另一个结构来保存计数。等等。没有比顺序遍历更快地搜索列表的神奇方法了。
  • @Yatendra Goel Java 可以在不到一秒的时间内迭代包含数千(甚至数十万)个对象的列表。
【解决方案2】:

你可以使用Collections类:

public static int frequency(Collection<?> c, Object o)

返回指定集合中等于指定对象的元素数。更正式地说,返回集合中元素 e 的数量,使得 (o == null ? e == null : o.equals(e))。

如果您需要多次计算长列表的出现次数,我建议您使用HashMap 来存储计数器并在向列表中插入新项目时更新它们。这将避免计算任何类型的计数器..但当然你不会有索引。

HashMap<Item, Integer> counters = new HashMap<Item, Integer>(5000);
ArrayList<Item> items = new ArrayList<Item>(5000);

void insert(Item newEl)
{
   if (counters.contains(newEl))
     counters.put(newEl, counters.get(newEl)+1);
   else
     counters.put(newEl, 1);

   items.add(newEl);
 }

最后一个提示:您可以使用其他集合框架(如 Apache Collections)并使用描述为的 Bag 数据结构

定义一个集合,计算对象在集合中出现的次数。

这正是你所需要的......

【讨论】:

  • 哇从来不知道这种方法。 Javadoc 在这里找到:java.sun.com/javase/6/docs/api/java/util/…
  • 你的第一种方法更适合我的需要。但是有一个问题。如果我在列表中找到多个项目,那么如何从列表中检索其他项目?
  • 如果它们相等,为什么还要检索它们呢?你已经知道里面是什么了!或者有没有输入你的equals比较的字段?或者您希望做的不仅仅是检索,比如删除?
  • 你的意思是counters.containsKey(newEl)
【解决方案3】:

正如其他受访者已经说过的,如果您坚定地致力于将项目存储在无序的 ArrayList 中,那么计数项目将花费 O(n) 时间,其中 n 是列表中的项目数。在 SO,我们提供建议,但我们不做魔术!

正如我刚才所暗示的,如果列表的搜索次数多于修改次数,那么保持排序可能是有意义的。如果您的列表已排序,那么您可以在 O(log n) 时间内找到您的项目,这要快得多;如果您的hashcode 实现与您的equals 相得益彰,那么所有相同的项目将彼此相邻。

另一种可能性是并行创建和维护两个数据结构。您可以使用 HashMap 包含您的项目作为键和它们的计数作为值。每当您的列表更改时,您有义务更新第二个结构,但项目计数查找将是 o(1)。

【讨论】:

    【解决方案4】:

    我可能是错的,但在我看来,您真正想要的数据结构可能是Multiset(来自google-collections/guava)而不是List。它允许倍数,不像Set,但实际上并不关心顺序。鉴于此,它有一个 int count(Object element) 方法可以完全满足您的需求。而且由于它不是一个列表并且具有由HashMap 支持的实现,因此获得计数的效率要高得多。

    【讨论】:

      【解决方案5】:

      感谢您提出的所有好建议。但是下面这段代码真的非常有用,因为我们没有任何可以提供出现次数的 List 搜索方法。

      void insert(Item newEl) 
      { 
         if (counters.contains(newEl)) 
           counters.put(newEl, counters.get(newEl)+1); 
         else 
           counters.put(newEl, 1); 
      
         items.add(newEl); 
       } 
      

      感谢杰克。好帖子。

      谢谢,

      比诺德·苏曼

      http://binodsuman.blogspot.com

      【讨论】:

        【解决方案6】:

        我知道这是一篇旧帖子,但由于我没有看到哈希映射解决方案,我决定在哈希映射上添加一个伪代码,以供将来需要它的任何人使用。假设 arraylist 和 Float 数据类型。

         Map<Float,Float> hm = new HashMap<>();
         for(float k : Arralistentry) {
         Float j = hm.get(k);
         hm.put(k,(j==null ? 1 : j+1));
         }
         for(Map.Entry<Float, Float> value : hm.entrySet()) {
        System.out.println("\n" +value.getKey()+" occurs : "+value.getValue()+" times");
          }
        

        【讨论】:

          猜你喜欢
          • 2011-07-02
          • 1970-01-01
          • 1970-01-01
          • 2019-01-15
          • 1970-01-01
          • 2014-03-18
          • 2013-11-13
          • 2014-10-16
          • 2015-03-20
          相关资源
          最近更新 更多