次の簡単なLINQコード
string[] words = { "hello", "wonderful", "linq", "beautiful", "world" };
// Get only short words
var shortWords =
from Word in words
where Word.Length <= 5
select Word;
// Print each Word out
shortWords.Dump();
次のようにリスト内包表記を使用して、pythonに変換できます。
words = ["hello", "wonderful", "linq", "beautiful", "world"]
shortWords = [x for x in words if len(x) <=5]
print shortWords
(警告:マンモスが先に答えます。最初の水平線までの部分がtl; drセクションになると思います)
Python guru ...としての資格があるかどうかはわかりませんが、Pythonでの反復についてはしっかりと把握しているので、試してみましょう:)
まず、Afaik、LINQクエリは遅延して実行されます-その場合、ジェネレーター式はより近いPythonの概念です(どちらの方法でも、リスト、辞書、セットの内包表記は概念的には単なるジェネレーター式のフィードです)リスト/辞書/セットコンストラクタに!).
また、概念的な違いもあります。LINQは、名前が示すように、データ構造のクエリに使用されます。リスト/ディクショナリ/セット内包は、これの可能な適用です(例えば、リストのアイテムのフィルタリングと投影)。したがって、実際にはそれほど一般的ではありません(後で説明するように、LINQに組み込まれている多くのものは組み込まれていません)。同様に、ジェネレーター式は、1回限りのフォワードイテレーターをインプレースで作成する方法です(私はそれをジェネレーター関数のラムダと見なしたいのですが、醜い、長いキーワードがない場合のみです))。複雑なクエリを記述する方法ではありません。はい、重複しますが、同一ではありません。 PythonでLINQのすべての機能が必要な場合は、本格的なジェネレーターを作成する必要があります。または、ビルトインおよびitertools
の多数の強力なジェネレーターを組み合わせます。
今、Python対応するLINQ機能に対応するJon Skeetは、
投影:_(x.foo for ...)
_
フィルタリング:_(... if x.bar > 5)
_
- 結合(x.fooのx結合yはy.barと等しい)
一番近いのは_((x_item, next(y_item for y_item in y if x_item.foo == y_item.bar)) for x_item in x)
_でしょう。
これは、各x_itemのy全体を反復するのではなく、最初の一致のみを取得することに注意してください。
- グループ結合(x.fooのx結合yはy.barからgに等しい)
これは難しいです。 Pythonには匿名型はありませんが、___dict__
_をいじることを気にしない場合は、自明です。
_class Anonymous(object):
def __init__(self, **kwargs):
self.__dict__ = kwargs
_
次に、_(Anonymous(x=x, y=y) for ...)
_を実行して、それぞれの値を持つx
およびy
メンバーを持つオブジェクトのリストを取得できます。正しいことは、通常、適切なクラス、たとえばXYのコンストラクターに結果を供給することです。
- グループ化(x.fooでx.fooをグループ化)
今それは毛むくじゃらになります...組み込み方法はありません、アファイク。しかし、必要に応じて自分で定義できます。
_from collections import defaultdict
def group_by(iterable, group_func):
groups = defaultdict(list)
for item in iterable:
groups[group_func(item)].append(item)
return groups
_
例:
_>>> from operator import attrgetter
>>> group_by((x.foo for x in ...), attrgetter('bar'))
defaultdict(<class 'list'>, {some_value_of_bar: [x.foo of all x where x.bar == some_value_of_bar], some_other_value_of_bar: [...], ...})
_
ただし、グループ化するものはすべてハッシュ可能にする必要があります。これを回避することは可能であり、公的な需要があれば私は刺します。しかし、今のところ、私は怠惰です:)
結果に対して.values()
を呼び出すことで、グループ化された値なしでグループのイテラブルを返すこともできます(もちろん、thatをlist
にフィードできますインデックスを作成して数回繰り返すことができるものを取得します)。しかし、グループ値が必要ないかどうかは誰にもわかりません...
- 順序付け(orderby x.foo昇順、y.bar降順)
ソートには特別な構文が必要ですか?ビルトインsorted
もイテラブルで機能します:sorted(x % 2 for x in range(10))
またはsorted(x for x in xs, key=attrgetter('foo'))
。デフォルトでは昇順でソートされ、キーワード引数reverse
は降順を示します。
残念ながら、複数の属性によるafaikソートは、特に昇順と降順を混合する場合はそれほど簡単ではありません。うーん...レシピのトピック?
- 中間変数(tmp = x.fooとします)
いいえ、内包表記やジェネレータ式では使用できません。名前が示すように、これらは式であることが想定されています(通常、1行または2行しかありません)。ただし、ジェネレーター関数では完全に可能です。
_(x * 2 for x in iterable)
_
中間変数を持つジェネレータとして書き直されました:
_def doubles(iterable):
for x in iterable:
times2 = x * 2
yield times2
_
フラット化:_(c for s in ("aa","bb") for c in s )
_
LINQ to Objectsはデリゲートを処理しますが、他のクエリプロバイダー(LINQ to SQLなど)は、実行可能なデリゲートを表示するだけでなく、クエリを記述する式ツリーで処理できることに注意してください。これにより、クエリをSQL(または他のクエリ言語)に変換できます。ここでも、Pythonがそのようなことをサポートしているかどうかはわかりません。ただし、LINQの重要な部分です。
Pythonはそのようなことは絶対に行いません。リスト式は、(おそらくネストされた)forループにプレーンリストを累積することに1対1で対応し、ジェネレータ式は1対1でジェネレータに対応します。 parser
およびast
モジュールが与えられた場合、理論的には内包を変換するためのライブラリを作成することが可能です。 SQLクエリ。しかし、誰も気にしません。
さて、あなたはいくつかの異なるものを区別する必要があります:
C#は、クエリ式でVBほど多くサポートしていませんが、次のようになりますdoesサポート:
select x.foo
)where x.bar > 5
)x join y on x.foo equals y.bar
)x join y on x.foo equals y.bar into g
)group x.foo by x.bar
)orderby x.foo ascending, y.bar descending
)let tmp = x.foo
)from x in y from z in x
)それらのうちいくつがPythonのリスト内包で直接サポートされているかはわかりません。
LINQ to Objectsはデリゲートを処理しますが、他のクエリプロバイダー(LINQ to SQLなど)は、実行可能なデリゲートを表示するだけでなく、クエリを記述する式ツリーで処理できることに注意してください。これにより、クエリをSQL(または他のクエリ言語)に変換できます。ここでも、Pythonがそのようなことをサポートしているかどうかはわかりません。ただし、LINQの重要な部分です。
asq Pythonパッケージを使用すると、ほとんどのことがPython LINQ-for-オブジェクト。asqを使用すると、Pythonの例は次のようになります。
from asq.initiators import query
words = ["hello", "wonderful", "linq", "beautiful", "world"]
shortWords = query(words).where(lambda x: len(x) <= 5)
私はPythonの第一人者ではありませんが、Pythonは実際にそれらすべてをサポートしているので、リスト内包表記をネストして、必要なすべてのラムダ式を含めることができるため、 。(ただし、リストの内包表記は、複雑になりすぎると読みにくくなる傾向があります...)が、それを実現するための「特定の構文」は含まれていません。
ほとんどの機能は次を使用して再現できます:-list comprehensionsまたはgenerators -ラムダ関数または組み込み関数(filter()
またはmap()
など)またはitertools
モジュールの関数
たとえば、次の動作をコピーする場合:
[ (k,v) for k,v in my_dict.items() if k.startswith("abc"]
。 map()
を使用することもできますif
の後の式になります。 filter()
を使用することもできますsorted()
を使用するだけmin()
を使用します、max()
またはitertools.groupby()
joinsまたはflatteningについては、「実行する必要があると思いますそれを手で」...
(常に Pythonクイックリファレンス が手元にあるとよい)