2010-10-13 2 views
42

Следующего простого кодом LINQПайтон список постижение против .NET 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(); 

может быть переведено на питон, используя список понимание следующим образом.

words = ["hello", "wonderful", "linq", "beautiful", "world"] 
shortWords = [x for x in words if len(x) <=5] 
print shortWords 
  • Является LINQ просто еще одна идея реализовать список понимание?
  • Какие примеры могут быть в том, что LINQ может выполнять, но перечислить понимание не может.
+4

Если вы ленивы в C# Рассмотрим написание вместо этого: words.Where (ш => w.Length <5) .dump(); – Moberg

+0

Как пояснялось в [этом эпическом объяснении монад] (http://www.youtube.com/watch?v=ZhuHCtR3xq8), LINQ тщательно разработан, чтобы быть монодичным, поэтому его можно строить простым, безопасным и эффективным способом , Монад и функциональное программирование быстро растут. Поэтому я предлагаю людям обратиться к ним в своих ответах. – nealmcb

+1

@nealmcb Монада важна только на языке, который не поддерживает разделяемое изменяемое состояние, так же как и статические методы, полезны только на языках, не поддерживающих первоклассные функции. Это способ обеспечить идеологическую чистоту, чтобы позволить парадигме программирования делать что-то, что не подходит для того, чтобы быть полным. Таким образом, монада никогда не будет возрастать по важности; это костыль, чтобы обойти ограничения, введенные самим собой. Другим примером может служить обобщение и динамическая типизация. – alcalde

ответ

49

(Предупреждение: мамонт отвечает вперед. Часть до первой горизонтальной линии делает хороший раздел tl; dr, я полагаю)

Я не уверен, что я квалифицируюсь как гуру Python ... но у меня есть твердое понимание на итерации на Python, так что давайте попробуйте :)

Прежде всего: запросы Afaik, LINQ выполняются лениво - если это так, выражения генератора представляют собой более близкую концепцию Python (в любом случае, функции list-, dict- и set понимают концептуально просто выражения генератора, list/dict/set constructor!).

Также существует концептуальная разница: LINQ для, как сказано в названии, для запросов структур данных. List-/dict-/set assrehensions - это возможное применение этого (например, фильтрация и проецирование элементов списка). Поэтому они на самом деле менее общие (как мы увидим, многие вещи, встроенные в LINQ, не встроены в них). Подобным образом, выражения генератора - это способ сформулировать одноразовый итератор вперед на месте (мне нравится думать об этом как лямбда для функций генератора, только без уродливого длинного ключевого слова;)), а не для описания сложного запроса , Они перекрываются, да, но они не идентичны. Если вы хотите использовать все возможности LINQ в Python, вам нужно будет написать полноценный генератор. Или объедините многочисленные мощные генераторы, встроенные и в itertools.


Теперь коллеги Python для возможности LINQ Джон Скит имени:

проекциях: (x.foo for ...)

Фильтрация: (... if x.bar > 5)

  • соединений (х присоединиться к у на x.foo equals y.bar)

Ближайшая вещь будет ((x_item, next(y_item for y_item in y if x_item.foo == y_item.bar)) for x_item in x), я полагаю.

Обратите внимание, что это не будет перебирать по всей y для каждого x_item, оно получит только первое совпадение.

  • Group присоединяется к (х присоединиться к у на x.foo приравнивает y.bar в г)

Это сложнее. Python не имеет анонимные типы, хотя они тривиальны сделать самостоятельно, если вы не возражаете, баловаться с __dict__:

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

Тогда мы могли бы сделать (Anonymous(x=x, y=y) for ...), чтобы получить список объектов, которые имеют x и y членов с соответствующими значениями. Правильная вещь обычно подает результаты конструктору класса approriate, скажем, XY.

  • Группировка (группа x.foo по x.bar)

Теперь он получает волосатой ... нет встроенного способа, AFAIK. Но мы можем определить его OURSELF, если это необходимо:

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: [...], ...}) 

Это требует, что мы группа по быть hashable, хотя. Этого можно избежать, и я сделаю удар, если будет общественный спрос. Но сейчас, я ленивый :)

Мы также можем просто вернуть итератор групп без ценностей, которые мы сгруппированных по, по телефону .values() на результат (конечно, мы можем кормить что к 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 дает убывающий порядок.

Увы, сортировка по афайкам по нескольким атрибутам не так проста, особенно при смешении восходящего и нисходящего. Хм ... тема для рецепта?

  • Промежуточных переменными (пусть 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 к объектам имеет дело с делегаты, другие поставщики запросов (например, LINQ to SQL) могут обрабатывать деревья выражений, которые описывают запрос instea d просто представить исполняемых делегатов. Это позволяет преобразовать запрос в SQL (или другие языки запросов) - опять же, я не знаю, поддерживает ли Python такую ​​вещь или нет. Однако это значительная часть LINQ.

Python определенно не делает этого. Выражения списка соответствуют взаимно однозначным для накопления простого списка в (возможно, вложенном) для цикла, генераторные выражения соответствуют друг другу одному генератору. Учитывая, что в модуле parser и ast возможно теоретически , чтобы написать библиотеку для преобразования понимания, например. SQL-запрос. Но никто не заботится.

+2

Чтобы сделать некоторые из этих более «Pythonic» (то есть native/idiomatic), проверьте «python» 'collections.namedtuple' и' itertools.groupby' – Ghopper21

+2

Также для выравнивания: 'itertools.chain' – Ghopper21

19

Ну, вам нужно различать несколько разных вещей:

  • LINQ стандартных операторов запросов
  • выражений LINQ запросов в C#
  • выражения LINQ запроса в VB

C# не поддерживает столько запросов выражения, сколько VB, но вот что он делает suppor т:

  • Проекция (select x.foo)
  • Filtering (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.

+1

«Все, что вы можете сделать, я могу сделать лучше ...» См. Pynq (https://github.com/heynemann/pynq/wiki). Почему бы не сравнить апельсины с апельсинами? Во всяком случае, перечислительные методы не сопоставимы с LINQ, потому что они служат совершенно другой цели. В тех случаях, когда LINQ подчеркивает выразительность в отношении производительности, понимание списков подчеркивает эффективность над выразительностью. Они работают аналогично тому, как вы переопределяете метод .Equals() в C# через передачу в IEqualsComparator, за исключением того, что вы передаете генераторную функцию в конструктор итератора (ex list). Я не гуру, но это довольно простой материал на питоне. –

+1

@EvanPlaice - это не генераторы, разница заключается в использовании скобок и скобок, см. Http://stackoverflow.com/questions/47789/generator-expressions-vs-list-comprehension, а в .Net Linq всегда в памяти и может сгенерировано с ключевым словом yield (аналогично генераторам, но без ограничения на одно использование). –

2

Я не гуру Python, но я бы сказал, что Python фактически поддерживает все из них, поскольку вы можете вставлять списки и включать все необходимые лямбда-выражения. (понимание списков, как правило, трудно читать, если они становятся слишком сложными, хотя ...), но нет, он не содержит «конкретного синтаксиса» для выполнения всего этого.

Большинство функций может быть воспроизведено с помощью: - списковых или генераторов - лямбда-функции или встроенные функции (как filter() или map()) или функции из itertools модуля

Например, если вы хотите, чтобы скопировать поведение:

  • проекциях: т hat будет левой частью понимания списка ... которые могут быть одиночными значениями, но также кортежей. ex: [ (k,v) for k,v in my_dict.items() if k.startswith("abc"]. Вы также можете использовать map()
  • Фильтрация: это будет выражение справа, после if. Вы также можете использовать filter()
  • заказа: просто использовать встроенный sorted()
  • Группировка или агрегаты: используйте встроенный min(), max() или itertools.groupby()

Относительно присоединяется или сплющивание, я думаю, вам придется «делать это вручную» ...

(Всегда хорошо иметь Python Quick Reference при достижении)

15

С помощью пакета Python asq вы можете легко сделать большинство вещей на Python, что вы можете сделать на C#, используя LINQ-for-objects. Используя ASQ, ваш пример Python становится:

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

Ссылка была пробовлена: https://pypi.python.org/pypi/asq/1.0 – Anytoe

Смежные вопросы