150

Python は、熱心な iterable の長さを取得するための優れた方法を提供しますlen(x)。しかし、ジェネレータ内包表記と関数で表される遅延イテラブルに似たものは見つかりませんでした。もちろん、次のようなものを書くのは難しくありません。

def iterlen(x):
  n = 0
  try:
    while True:
      next(x)
      n += 1
  except StopIteration: pass
  return n

しかし、自転車を再実装しているという感覚は拭えません。

(関数を入力しているときに、考えが頭に浮かびました。引数を「破棄」するため、そのような関数は実際には存在しない可能性があります。ただし、私の場合は問題ではありません)。

PS: 最初の回答について - はい、次のようなものlen(list(x))も機能しますが、メモリの使用量が大幅に増加します。

PPS: 再チェック... PS は無視してください。試行中に間違いを犯したようです。正常に動作します。ご迷惑おかけして申し訳ありません。

4

9 に答える 9

281

最も簡単な方法は、おそらくsum(1 for _ in gen)gen がジェネレーターの場所です。

于 2011-08-28T20:04:50.497 に答える
41

一般的なケースでは実行できないため、1 つもありません。怠惰な無限ジェネレーターがある場合はどうでしょうか。例えば:

def fib():
    a, b = 0, 1
    while True:
        a, b = b, a + b
        yield a

これは終了することはありませんが、フィボナッチ数を生成します。を呼び出すことで、必要な数のフィボナッチ数を取得できますnext()

アイテムの数を本当に知る必要がある場合は、一度に直線的に繰り返すことはできないため、通常のリストなどの別のデータ構造を使用してください。

于 2008-12-25T18:53:39.983 に答える
19
def count(iter):
    return sum(1 for _ in iter)

またはさらに良い:

def count(iter):
    try:
        return len(iter)
    except TypeError:
        return sum(1 for _ in iter)

反復可能でない場合は、TypeError.

または、ジェネレーターで特定のものをカウントする場合は、次のようにします。

def count(iter, key=None):
    if key:
        if callable(key):
            return sum(bool(key(x)) for x in iter)
        return sum(x == key for x in iter)
    try:
        return len(iter)
    except TypeError:
        return sum(1 for _ in iter)
于 2012-07-13T04:22:31.997 に答える
8

enumerate() を使用して、生成されたデータ ストリームをループし、最後の数値 (アイテムの数) を返すことができます。

itertools.count() を itertools.izip() で使用しようとしましたが、うまくいきませんでした。これは私が思いついた最良/最短の答えです:

#!/usr/bin/python

import itertools

def func():
    for i in 'yummy beer':
        yield i

def icount(ifunc):
    size = -1 # for the case of an empty iterator
    for size, _ in enumerate(ifunc()):
        pass
    return size + 1

print list(func())
print 'icount', icount(func)

# ['y', 'u', 'm', 'm', 'y', ' ', 'b', 'e', 'e', 'r']
# icount 10

Kamil Kisiel のソリューションの方がはるかに優れています。

def count_iterable(i):
    return sum(1 for e in i)
于 2008-12-25T19:55:48.017 に答える
6

定義により、ジェネレーターのサブセットのみが特定の数の引数の後に返されます (事前に定義された長さを持ちます)。さらに、これらの有限ジェネレーターのサブセットのみが予測可能な終了を持ちます (ジェネレーターにアクセスすると、副作用が生じる可能性があります)。ジェネレーターを早期に停止する可能性があります)。

ジェネレーターに長さメソッドを実装する場合は、最初に「長さ」と見なすものを定義する必要があります (要素の総数ですか? 残りの要素の数ですか?)、次にジェネレーターをクラスにラップします。次に例を示します。

class MyFib(object):
    """
    A class iterator that iterates through values of the
    Fibonacci sequence, until, optionally, a maximum length is reached.
    """

    def __init__(self, length):
        self._length = length
        self._i = 0

     def __iter__(self):
        a, b = 0, 1
        while not self._length or self._i < self._length:
            a, b = b, a + b
            self._i += 1
            yield a

    def __len__(self):
        "This method returns the total number of elements"
        if self._length:
            return self._length
        else:
            raise NotImplementedError("Infinite sequence has no length")
            # or simply return None / 0 depending
            # on implementation

使用方法は次のとおりです。

In [151]: mf = MyFib(20)

In [152]: len(mf)
Out[152]: 20

In [153]: l = [n for n in mf]

In [154]: len(l)
Out[154]: 20

In [155]: l
Out[155]: 
[1,
 1,
 2,
...
6765]


In [156]: mf0 = MyFib(0)

In [157]: len(mf0)
---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
<ipython-input-157-2e89b32ad3e4> in <module>()
----> 1 len(mf0)

/tmp/ipython_edit_TWcV1I.py in __len__(self)
     22             return self._length
     23         else:
---> 24             raise NotImplementedError
     25             # or simply return None / 0 depending
     26             # on implementation

NotImplementedError: 

In [158]: g = iter(mf0)

In [159]: l0 = [g.next(), g.next(), g.next()]

In [160]: l0
Out[160]: [1, 1, 2]
于 2013-03-28T19:51:29.567 に答える
5

reduce(function, iterable[, initializer])を使用して、メモリ効率の高い純粋に機能的なソリューションを実現します。

>>> iter = "This string has 30 characters."
>>> reduce(lambda acc, e: acc + 1, iter, 0)
30
于 2013-09-05T07:32:31.763 に答える
5

more_itertools簡単なソリューションのパッケージを試してください。例:

>>> import more_itertools

>>> it = iter("abcde")                                         # sample generator
>>> it
<str_iterator at 0x4ab3630>

>>> more_itertools.ilen(it)
5

別の適用例については、この投稿を参照してください。

于 2016-12-12T17:57:35.310 に答える
1

lenこれはハックですが、一般的な iterable で作業したい(途中で消費する) 場合は、独自のバージョンの を作成できますlen

このlen関数は基本的に次のものと同等です (ただし、実装では通常、余分なルックアップを避けるためにいくつかの最適化が提供されます)。

def len(iterable):
    return iterable.__len__()

new_lenしたがって、それを試すように定義できます。__len__存在しない場合は、イテラブルを消費して自分で要素の数を数えます。

def new_len(iterable):
    try:
      return iterable.__len__()
    except AttributeError:
      return sum(1 for _ in iterable)

上記は Python 2/3 で動作し、(私の知る限り) 考えられるすべての種類のイテラブルをカバーする必要があります。

于 2016-03-14T18:24:23.270 に答える