【问题标题】:Get size of an Iterable in Java在 Java 中获取 Iterable 的大小
【发布时间】:2012-07-20 21:19:51
【问题描述】:

我需要在 Java 中计算出 Iterable 中的元素数量。 我知道我可以做到:

Iterable values = ...
it = values.iterator();
while (it.hasNext()) {
  it.next();
  sum++;
}

我也可以这样做,因为我不再需要 Iterable 中的对象:

it = values.iterator();
while (it.hasNext()) {
  it.remove();
  sum++;
}

一个小规模的基准测试并没有显示出太大的性能差异,对于这个问题有什么 cmets 或其他想法吗?

【问题讨论】:

  • 为什么?两者都是一个非常糟糕的主意,因为两者都是 O(N)。您应该尽量避免必须对集合进行两次迭代。
  • 你的第二个甚至不应该工作。你不能在没有事先打电话给next()的情况下打电话给remove()。

标签: java iterable


【解决方案1】:

TL;DR:使用伟大的Guava 库的实用方法Iterables.size(Iterable)。

在你的两个代码sn-ps中,你应该使用第一个,因为第二个会删除values中的所有元素,所以之后它是空的。像大小这样的简单查询更改数据结构是非常出乎意料的。

对于性能,这取决于您的数据结构。例如,如果它实际上是ArrayList,则从头删除元素(您的第二种方法正在执行的操作)非常慢(计算大小变为 O(n*n) 而不是 O(n),因为它应该是) .

一般来说,如果values 有可能实际上是Collection 而不仅仅是Iterable,请检查此并致电size() 以防万一:

if (values instanceof Collection<?>) {
  return ((Collection<?>)values).size();
}
// use Iterator here...

对size() 的调用通常比计算元素的数量要快得多,而这个技巧正是Guava 的Iterables.size(Iterable) 为您所做的。

【讨论】:

  • 他说他对这些元素不感兴趣,也不关心它们是否被删除。
  • 小说明:它将从values中删除元素
  • 但代码的其他部分可能仍在使用相同的 Iterable。如果不是现在,也许在未来。
  • 我建议让 Google Guava 的答案更加突出。没有理由让人们再次编写这段代码,即使它微不足道。
  • 如果你使用 Java 8,创建一个 Stream 并在其中计数元素为:Stream.of(myIterable).count()
【解决方案2】:

如果您使用的是 java 8,您可以使用:

Iterable values = ...
long size = values.spliterator().getExactSizeIfKnown();

仅当可迭代源具有确定的大小时才会起作用。大多数集合拆分器都可以,但如果它来自HashSet或ResultSet例如,您可能会遇到问题。

您可以查看javadoc here.

如果 Java 8 不是一个选项,或者如果您不知道可迭代的来源,您可以使用与 guava 相同的方法:

  if (iterable instanceof Collection) {
        return ((Collection<?>) iterable).size();
    } else {
        int count = 0;
        Iterator iterator = iterable.iterator();
        while(iterator.hasNext()) {
            iterator.next();
            count++;
        }
        return count;
    }

【讨论】:

  • 来人,给这家伙一枚勋章。
  • Sort 对我不起作用。 New Bee 的回答对我有用。
【解决方案3】:

这可能有点晚了,但可能会对某人有所帮助。我在我的代码库中遇到了与Iterable 类似的问题,解决方案是使用for each 而不显式调用values.iterator();。

int size = 0;
for(T value : values) {
   size++;
}

【讨论】:

  • 对我来说,这是一种直观的方法,我很欣赏。几分钟前刚用过。谢谢。
  • 是的,它很直观,但遗憾的是,您必须禁止使用未使用的警告值...
  • 感谢这个解决方案,它确实返回了对象的大小。唯一的缺点是,如果您想稍后再次迭代同一个对象,那么首先您应该以某种方式重置它。
【解决方案4】:

您可以将您的可迭代对象转换为列表,然后在其上使用 .size()。

Lists.newArrayList(iterable).size();

为清楚起见,上述方法将需要以下导入:

import com.google.common.collect.Lists;

【讨论】:

  • Lists 是 Guava 类
【解决方案5】:

严格来说,Iterable 没有大小。把数据结构想象成一个循环。

并考虑以下 Iterable 实例,没有大小:

    new Iterable(){

        @Override public Iterator iterator() {
            return new Iterator(){

                @Override
                public boolean hasNext() {
                    return isExternalSystemAvailble();
                }

                @Override
                public Object next() {
                    return fetchDataFromExternalSystem();
                }};
        }};

【讨论】:

    【解决方案6】:

    java 8 及以上

    StreamSupport.stream(data.spliterator(), false).count();
    

    【讨论】:

      【解决方案7】:

      我会选择it.next(),原因很简单,next() 保证可以实现,而remove() 是可选操作。

      E next()
      

      返回迭代中的下一个元素。

      void remove()
      

      从底层集合中移除迭代器返回的最后一个元素(可选操作)。

      【讨论】:

      • 虽然这个答案在技术上是正确的,但它具有很大的误导性。调用remove 已经被指出是计算Iterator 元素的错误方法,所以我们不打算做的事情是否实现并不重要。
      • 答案的哪一部分是误导性的?而在remove被实现的情况下,怎么会用不上呢?顺便说一句,downvotes 通常用于错误的答案或给出错误建议的答案。我看不出这个答案有什么资格。
      【解决方案8】:

      对我来说,这些只是不同的方法。第一个使您正在迭代的对象保持不变,而第二个则使其为空。 问题是你想做什么。 删除的复杂性取决于可迭代对象的实现。 如果您使用 Collections - 只需获得 Kazekage Gaara 建议的大小 - 它通常是最好的方法性能明智。

      【讨论】:

        【解决方案9】:

        您为什么不简单地使用Collection 上的size() 方法来获取元素的数量?

        Iterator 只是为了迭代,没有别的。

        【讨论】:

        • 谁说他在使用集合? :-)
        • 您正在使用支持删除元素的迭代器。如果您在进入迭代器循环之前选择了大小,则需要小心删除并相应地更新值。
        • 他可能没有要查看大小的集合的示例:他可能正在调用仅返回 Iterable 的第三方 API 方法。
        • 这个答案混淆了Iterator 和Iterable。正确方法见投票答案。
        【解决方案10】:

        我们可以简单地对 ArrayList 中的可迭代对象进行类型转换并获取其大小,而不是使用循环和计算每个元素或使用第三方库。

        ((ArrayList) iterable).size();
        

        【讨论】:

        • 并非所有可迭代对象都可以转换为 ArrayList
        猜你喜欢
        • 1970-01-01
        • 2010-12-13
        • 1970-01-01
        • 2012-05-16
        • 2016-06-07
        • 1970-01-01
        • 2011-09-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多