-1

Python のユーザーが作成したリスト内包表記の構造のうち、最も有用なものはどれですか?

次の 2 つの量指定子を作成しました。これらを使用して、さまざまな検証操作を行います。

def every(f, L): return not (False in [f(x) for x in L])
def some(f, L): return True in [f(x) for x in L]

最適化されたバージョン (Python 2.5+ が必要) が以下に提案されました。

def every(f, L): return all(f(x) for x in L)
def some(f, L): return any(f(x) for x in L) 

それで、それはどのように機能しますか?

"""For all x in [1,4,9] there exists such y from [1,2,3] that x = y**2"""
answer = every([1,4,9], lambda x: some([1,2,3], lambda y: y**2 == x))

このような操作を使用すると、次のようなスマートな検証を簡単に実行できます。

"""There exists at least one bot in a room which has a life below 30%"""
answer = some(bots_in_this_room, lambda x: x.life < 0.3)

など、非常に複雑な質問でも、そのような量指定子を使用して答えることができます。もちろん、Python には無限リストはありません (Haskell ではありません :) ) が、Python のリスト内包表記は非常に実用的です。

あなた自身のお気に入りのリスト内包構造体はありますか?

PS: ほとんどの人が質問に答えずに提示された例を批判する傾向があるのはなぜでしょうか? 質問は、実際にはお気に入りのリスト内包表記に関するものです。

4

4 に答える 4

13

anyall2.5 からの標準 Python の一部です。これらの独自のバージョンを作成する必要はありません。また、公式バージョンの評価anyall可能な限りショートサーキットして、パフォーマンスの向上を与えます。バージョンは常にリスト全体を反復します。

any述語を受け入れるバージョンが必要な場合は、既存のandall関数を活用する次のようなものを使用します。

def anyWithPredicate(predicate, l): return any(predicate(x) for x in l) 
def allWithPredicate(predicate, l): return all(predicate(x) for x in l) 

ただし、これらの関数の必要性は特にわかりません。入力をあまり節約できないためです。

また、既存の標準 Python 関数を、同じ名前で動作が異なる独自の関数で非表示にすることは、悪い習慣です。

于 2009-11-23T15:48:23.280 に答える
5

リスト内包表記 (略して LC) が同等のジェネレーター式 (略して GE、つまり、角括弧の代わりに丸括弧を使用して、一度に 1 つの項目を生成するよりも実質的に有用であるケースはそれほど多くありません。 「最初にすべてまとめて」よりも)。

Python の 1 つまたは別のバージョンでの最適化とガベージ コレクションの気まぐれに応じて、一度にリストを保持するために余分なメモリを「投資」することで、少し余分な速度を得ることができますが、それは LC とGE。

基本的に、GE と比較して LC を大幅に活用するには、シーケンスで「複数のパス」を本質的に必要とするユースケースが必要です。このような場合、GE ではパスごとに 1 回シーケンスを生成する必要がありますが、LC では、シーケンスを 1 回生成してから複数のパスを実行できます (生成コストは 1 回のみ支払います)。GE / LC が単純に再起動できない基礎となる反復子 (たとえば、実際には Unix パイプである「ファイル」) に基づいている場合、複数の世代も問題になる可能性があります。

たとえば、f空白で区切られた多数の (テキスト表現の) 数値 (あちこちの改行、空行などを含む) を含む、空でないオープン テキスト ファイルを読んでいるとします。次のいずれかの GE を使用して、一連の数字に変換できます。

G = (float(s) for line in f for s in line.split())

または LC:

L = [float(s) for line in f for s in line.split()]

どちらの方がよいですか?何をしているかによって異なります (つまり、ユースケース!)。たとえば、合計だけが必要な場合は、sum(G) と sum(L) も同様に機能します。平均が必要な場合は、リストには sum(L)/len(L) で問題ありませんが、ジェネレーターでは機能しません。「f の再起動」が難しいため、中間リストを回避するには、次のようにする必要があります。次のようにします。

tot = 0.0
for i, x in enumerate(G): tot += x
return tot/(i+1)

ほど機敏で、速く、簡潔で、エレガントなところはありませんreturn sum(L)/len(L)

sorted(G)は (必然的に) リストを返すことを覚えておいてくださいL.sort()したがって、この場合、(インプレースである) は大まかに同等です。そのため、ソートが必要な場合は、単に簡潔さのためにジェネレーターが好まれることがよくあります。

全体として、L は と同等であるため、 ;-)list(G)のような 1 つの短くて発音可能で明白な単語の代わりに、句読点 (丸括弧の代わりに角括弧) を使用して表現する機能に非常に興奮することは困難です。listLC はこれですべてです -- 句読点ベースの構文のショートカットlist(some_genexp)...!

于 2009-11-23T16:38:34.553 に答える
4

このソリューションは、一般的に悪い考えであるビルトインを隠します。ただし、使用法はかなりPythonicに感じられ、元の機能が保持されます.

テストに基づいてこれを潜在的に最適化する方法がいくつかあることに注意してください。たとえば、インポートをモジュールレベルに移動し、f のデフォルトを None に変更して、デフォルトのラムダを使用する代わりにテストします。

def any(l, f=lambda x: x):
    from __builtin__ import any as _any
    return _any(f(x) for x in l)

def all(l, f=lambda x: x):
    from __builtin__ import all as _all
    return _all(f(x) for x in l)

検討のためにそれをそこに置いて、潜在的に汚いことをすることについて人々がどう思うかを見るだけです。

于 2009-11-23T16:06:35.150 に答える
2

参考までに、 Python 3.xのモジュールのドキュメントitertoolsには、いくつかの非常に優れたジェネレーター関数がリストされています。

于 2009-11-23T16:44:59.033 に答える