programing

Python의 목록 이해와 .NET LINQ

randomtip 2021. 1. 14. 08:13
반응형

Python의 목록 이해와 .NET LINQ


다음과 같은 간단한 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();

다음과 같이 list comprehension을 사용하여 파이썬으로 번역 할 수 있습니다.

words = ["hello", "wonderful", "linq", "beautiful", "world"]
shortWords = [x for x in words if len(x) <=5]
print shortWords
  • LINQ는 목록 이해를 구현하는 또 다른 아이디어입니까?
  • LINQ는 할 수 있지만 목록 이해는 할 수없는 예가 될 수 있습니다.

(경고 : Mammoth 대답이 앞서 있습니다. 첫 번째 수평선까지의 부분은 좋은 tl; dr 섹션을 만듭니다.)

Python 전문가 자격이 있는지 확실하지 않지만 Python의 반복에 대한 확실한 이해가 있으므로 시도해 보겠습니다. :)

먼저 : Afaik, LINQ 쿼리는 느리게 실행됩니다.이 경우 생성기 표현식은 더 가까운 Python 개념입니다 (방법, 목록, 사전 및 집합 이해는 개념적으로 목록 / 사전 / 집합 생성자에 제공되는 생성기 표현식입니다! ).

또한 개념적 차이가 있습니다. LINQ는 이름에서 알 수 있듯이 데이터 구조를 쿼리하기위한 것입니다. List- / dict- / set comprehensions는이를 적용 할 수 있습니다 (예 : 목록의 항목 필터링 및 투영). 따라서 실제로는 덜 일반적입니다 (앞으로 보 겠지만 LINQ에 내장 된 많은 것들이 내장되어 있지 않습니다). 마찬가지로 제너레이터 표현식은 일회성 순방향 반복기를 제자리에서 공식화하는 방법이며 (제너레이터 함수를위한 람다로 생각하고, 추악하고 긴 키워드없이 만;)) 복잡한 쿼리를 설명하는 방법이 아닙니다. . 예, 겹치지 만 동일하지는 않습니다. Python에서 LINQ의 모든 기능을 사용하려면 완전한 생성기를 작성해야합니다. 또는 내장 된 수많은 강력한 생성기를 itertools.


이제 LINQ 기능에 대한 Python 대응 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 조인 x x.foo의 y는 y.bar에서 g와 같음)

이것은 더 어렵습니다. 파이썬에는 익명 유형이 없지만, 엉망이 되어도 괜찮다면 스스로하기가 쉽지 않습니다 __dict__.

class Anonymous(object):
    def __init__(self, **kwargs):
        self.__dict__ = kwargs

그런 다음, 우리가 할 수있는 (Anonymous(x=x, y=y) for ...)이되는 객체의 목록을 얻을 수 xy각각의 값 회원. 옳은 일은 일반적으로 XY와 같은 적절한 클래스의 생성자에게 결과를 제공하는 것입니다.

  • 그룹화 (x.foo를 x.bar로 그룹화)

이제 털이 많아요 ... 내장 방법이 없습니다, afaik. 하지만 필요한 경우 스스로 정의 할 수 있습니다.

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()결과에 (물론 우리가 먹을 수 그것을 위해 list우리가 인덱스 할 수있는 뭔가를 얻을 수 및 반복 처리를 여러 번). 하지만 그룹 가치가 필요하지 않은지 누가 알겠습니까?

  • 정렬 (순서 : x.foo 오름차순, y.bar 내림차순)

정렬에는 특별한 구문이 필요합니까? 내장은 sortediterables 에서도 작동합니다 : sorted(x % 2 for x in range(10))또는 sorted(x for x in xs, key=attrgetter('foo')). 기본적으로 오름차순으로 정렬되며 키워드 인수 reverse는 내림차순을 제공합니다.

아아, 여러 속성에 의한 afaik 정렬은 특히 오름차순과 내림차순을 혼합 할 때 쉽지 않습니다. 흠 ... 레시피 주제?

  • 중간 변수 (let tmp = x.foo)

아니요, 이해력이나 생성기 표현에서는 불가능합니다. 이름에서 알 수 있듯이 표현이어야합니다 (일반적으로 한두 줄에 걸쳐 있음). 하지만 제너레이터 함수에서는 완벽하게 가능합니다.

(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 definitely does no such thing. List expressions correspond one-to-one to accumulating a plain list in a (possibly nested) for-loop, generator expressions correspond one-to-one to a generator. Given the parser and ast module, it would be possible in theory to write a library for converting a comprehension into e.g. an SQL query. But nobody cares to.


Well, you need to distinguish between some different things:

  • LINQ standard query operators
  • LINQ query expressions in C#
  • LINQ query expressions in VB

C# doesn't support as much in query expressions as VB does, but here's what it does support:

  • Projections (select x.foo)
  • Filtering (where x.bar > 5)
  • Joins (x join y on x.foo equals y.bar)
  • Group joins (x join y on x.foo equals y.bar into g)
  • Grouping (group x.foo by x.bar)
  • Ordering (orderby x.foo ascending, y.bar descending)
  • Intermediate variables (let tmp = x.foo)
  • Flattening (from x in y from z in x)

I don't know how many of those are supported directly in Python's list comprehensions.

Note that although LINQ to Objects deals with delegates, other query providers (e.g. LINQ to SQL) can deal in expression trees which describe the query instead of just presenting executable delegates. This allows the query to be translated into SQL (or other query languages) - again, I don't know whether Python supports that sort of thing or not. It's a significant part of LINQ though.


By using the asq Python package you can easily do most things in Python that you can do in C# using LINQ-for-objects. Using asq, your Python example becomes:

from asq.initiators import query
words = ["hello", "wonderful", "linq", "beautiful", "world"]
shortWords = query(words).where(lambda x: len(x) <= 5)

I am no Python guru, but I would say that Python actually supports all of them as you can nest list comprehensions and include all the lambda expressions that you want. (list comprehensions tend to be hard to read if they get too complex, though...), but no it includes no "specific syntax" to accomplish all that.

Most of the functionality can be reproduced using : - list comprehensions or generators - lambda-functions or builtin functions (like filter() or map()) or functions from the itertools module

For instance, if you want to copy the behaviour of :

  • Projections : that would be the left part of a list-comprehension ... which can be single values but also tuples. ex : [ (k,v) for k,v in my_dict.items() if k.startswith("abc"]. You may also use map()
  • Filtering : that would be the expression on the right, after the if. You may also use filter()
  • Ordering : just use the built-in sorted()
  • Grouping or aggregates : use the builtin min(), max() or itertools.groupby()

Regarding joins or flattening, I think you would have to "to do it by hand"...

(Always good to have the Python Quick Reference at reach )

ReferenceURL : https://stackoverflow.com/questions/3925093/pythons-list-comprehension-vs-net-linq

반응형