web-dev-qa-db-ja.com

Pythonに最初の(反復可能な)組み込み関数がないのはなぜですか?

Python組み込み関数、first(iterable)およびany(iterable)にいくらか似ている]にall(iterable)がない理由があるのではないかと思っています。 (どこかstdlibモジュールに隠れているかもしれませんが、itertoolsには表示されません。)firstは、短絡発生器の評価を実行して、不要な(および潜在的に無限の数of)操作を回避できます;すなわち.

def identity(item):
    return item

def first(iterable, predicate=identity):
    for item in iterable:
        if predicate(item):
            return item
    raise ValueError('No satisfactory value found')

このようにして、次のようなことを表現できます。

denominators = (2, 3, 4, 5)
lcd = first(i for i in itertools.count(1)
    if all(i % denominators == 0 for denominator in denominators))

ジェネレーターが終了しないため、その場合は明らかにlist(generator)[0]を実行できません。

または、一致する正規表現の束がある場合(すべてが同じgroupdictインターフェースを持っている場合に便利です):

match = first(regex.match(big_text) for regex in regexes)

list(generator)[0]を避け、正の一致で短絡することにより、多くの不必要な処理を節約できます。

65
cdleary

イテレータがある場合は、そのnextメソッドを呼び出すだけです。何かのようなもの:

In [3]: (5*x for x in xrange(2,4)).next()
Out[3]: 10
47
liori

「first」と呼ばれるPypiパッケージ があり、これを行います:

>>> from first import first
>>> first([0, None, False, [], (), 42])
42

たとえば、最初の奇数を返すために使用する方法は次のとおりです。

>> first([2, 14, 7, 41, 53], key=lambda x: x % 2 == 1)
7

Trueであるかどうかに関係なく、イテレータから最初の要素を返すだけの場合は、次のようにします。

>>> first([0, None, False, [], (), 42], key=lambda x: True)
0

これは非常に小さなパッケージです。この関数のみが含まれ、依存関係はなく、Python 2および3で動作します。単一のファイルなので、インストールする必要さえありません。それを使用します。

実際、ここにソースコードのほとんどがあります(バージョン2.0.1から、MITライセンス)でリリースされたHynek Schlawackによる):

def first(iterable, default=None, key=None):
    if key is None:
        for el in iterable:
            if el:
                return el
    else:
        for el in iterable:
            if key(el):
                return el
    return default
13
Flimm

類似の質問 を最近尋ねました(今ではこの質問の複製としてマークされています)。私の懸念は、ジェネレーターの最初の真の値を見つける問題を解決するために組み込みonlyを使用したかったということでもありました。私自身の解決策はこれでした:

x = next((v for v in (f(x) for x in a) if v), False)

最初の正規表現一致(最初の一致パターンではない!)を見つける例では、これは次のようになります。

patterns = [ r'\d+', r'\s+', r'\w+', r'.*' ]
text = 'abc'
firstMatch = next(
  (match for match in
    (re.match(pattern, text) for pattern in patterns)
   if match),
  False)

(パターンだけが返された場合に行うように)述部を2回評価せず、内包表記でローカルのようなハックを使用しません。

しかし、ロジックが1つだけを使用するように指示する場所にネストされた2つのジェネレーターがあります。したがって、より良い解決策はニースでしょう。

10
Alfe

Itertoolsには「スライス」イテレーターがあります。 Pythonでよく知っているスライス操作をエミュレートします。あなたが探しているのはこれに似たものです:

myList = [0,1,2,3,4,5]
firstValue = myList[:1]

イテレータにitertoolsを使用する同等のもの:

from itertools import islice
def MyGenFunc():
    for i in range(5):
        yield i

mygen = MyGenFunc()
firstValue = islice(mygen, 0, 1)
print firstValue 
6
Zoran Pavlovic

あなたの質問にはあいまいさがあります。 firstの定義と正規表現の例は、ブールテストがあることを意味します。しかし、分母の例には明示的にif節があります。そのため、各整数が偶然に一致するのは偶然です。

Nextとitertools.ifilterの組み合わせは、あなたが望むものを提供するように見えます。

match = next(itertools.ifilter(None, (regex.match(big_text) for regex in regexes)))
6
A. Coady

Haskellは、関数take(または部分関数take 1、技術的に)。 Python Cookbook HaskellのtaketakeWhile、およびdropと同じ機能を実行するジェネレータラッパーが記述されています。

しかし、それが組み込みではない理由については、あなたの推測は私のものと同じくらい良いです。

4
Mark Rushakoff