以下简单的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转换为python,如下所示。
words = ["hello", "wonderful", "linq", "beautiful", "world"]
shortWords = [x for x in words if len(x) <=5]
print shortWords
答案 0 :(得分:58)
(警告:猛犸象回答。直到第一条水平线的部分是一个很好的tl; dr部分,我想)
我不确定自己是否有资格成为Python大师...但我对Python中的迭代有一个很好的把握,所以让我们试试:)
首先关闭:Afaik,LINQ查询被懒惰地执行 - 如果是这样的话,生成器表达式是一个更接近的Python概念(无论是哪种方式,列表,字典和集合理解在概念上只是生成器表达式被馈送到list / dict /设置构造函数!)。
此外,还有一个概念上的区别:正如名称所示,LINQ用于查询数据结构。 List- / dict- / set comprehensions可以应用于此(例如,过滤和投影列表的项目)。所以它们实际上不那么通用(正如我们将看到的,LINQ中内置的很多东西都不是内置的)。同样,生成器表达式是一种在某种程度上形成一次性前向迭代器的方法(我喜欢将它视为生成器函数的lambda,只有没有丑陋的long关键字;))而不是描述复杂查询的方法。它们重叠,是的,但它们并不相同。如果你想在Python中使用LINQ的所有功能,你将不得不编写一个完整的生成器。或者将itertools
内置的众多强大的生成器组合在一起。
现在,用于LINQ功能的Python同行Jon Skeet命名为:
预测:(x.foo for ...)
过滤:(... if x.bar > 5)
- 加入(x在y.foo上加入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连接y在x.foo上等于y.bar到g)
这更难。 Python没有匿名类型,但如果你不介意弄乱__dict__
,那么你自己做的很简单:
class Anonymous(object):
def __init__(self, **kwargs):
self.__dict__ = kwargs
然后,我们可以(Anonymous(x=x, y=y) for ...)
获取具有相应值的x
和y
成员的对象列表。
正确的做法通常是将结果提供给approriate类的构造函数,比如XY。
- 分组(按x.bar分组x.foo)
现在它变得毛茸茸......没有内置的方式,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降序排列)
排序需要特殊的语法吗?内置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 to Objects处理委托,但其他查询提供程序(例如LINQ to SQL)可以处理描述查询的表达式树,而不仅仅是呈现可执行委托。这允许将查询转换为SQL(或其他查询语言) - 再次,我不知道Python是否支持这种事情。但它是LINQ的重要组成部分。
Python绝对没有这样的东西。列表表达式一对一地对应于(可能嵌套的)for循环中的普通列表,生成器表达式与发生器一一对应。
给定parser
和ast
模块,理论上 可能会编写一个库,用于将理解转换为例如。一个SQL查询。但没有人关心。
答案 1 :(得分:24)
嗯,你需要区分一些不同的东西:
C#在查询表达式中不像VB那样支持,但这是支持支持的内容:
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的重要组成部分。
答案 2 :(得分:16)
通过使用asq Python包,您可以轻松地在Python中执行大部分操作,您可以使用LINQ-for-objects在C#中执行此操作。使用asq,您的Python示例变为:
from asq.initiators import query
words = ["hello", "wonderful", "linq", "beautiful", "world"]
shortWords = query(words).where(lambda x: len(x) <= 5)
答案 3 :(得分:4)
我不是Python大师,但我会说Python实际上支持所有这些,因为你可以嵌套列表推导并包含你想要的所有lambda表达式。 (如果列表理解过于复杂,那么它们往往难以阅读,但是......)但是没有包含任何“特定语法”来完成所有这些。
大多数功能可以使用以下方式复制:
- 列表推导或生成器
- lambda函数或内置函数(如filter()
或map()
)或itertools
模块中的函数
例如,如果要复制以下行为:
[ (k,v) for k,v in my_dict.items() if k.startswith("abc"]
。您也可以使用map()
if
之后右侧的表达式。您也可以使用filter()
sorted()
min()
,max()
或itertools.groupby()
关于加入或展平,我认为你必须“手工完成”......
(总是很高兴Python Quick Reference触手可及)