[英]Does C# have anything comparable to Python's list comprehensions?
I want to generate a list in C#. 我想在C#中生成一个列表。 I am missing python's list comprehensions.
我缺少python的列表理解。 Is there a C# way to create collections on the fly like list comprehensions or generator expressions do in python?
是否有C#方式像Python中的列表推导或生成器表达式那样快速创建集合?
If you are using C# 3.0 (VS2008) then LINQ to Objects can do very similar things: 如果您使用的是C#3.0(VS2008),则LINQ to Objects可以做非常相似的事情:
List<Foo> fooList = new List<Foo>();
IEnumerable<Foo> extract = from foo in fooList where foo.Bar > 10 select Foo.Name.ToUpper();
Matt has mentioned query expressions. 马特提到了查询表达式。 These are available for LINQ in general, by the way - not just LINQ to Objects.
顺便说一下,这些通常可用于LINQ-而不仅仅是LINQ to Objects。 (For example, the same query applied to a LINQ to SQL datacontext would execute the filter and projection on the database.)
(例如,对LINQ to SQL数据上下文应用相同的查询将在数据库上执行过滤器和投影。)
The query expressions in C# 3 are simply syntactic sugar over writing normal C# code - although query expressions usually end up calling extension methods . 尽管查询表达式通常最终会调用扩展方法,但C#3中的查询表达式只是写普通C#代码的语法糖。 (They don't have to, and the compiler doesn't care, but they usually do.) There are various things you can do with collections which aren't available in C# query expressions, but which are supported by method calls, so it's worth being aware of both kinds of syntax.
(它们不必这样做,并且编译器不在乎,但它们通常会这样做。)您可以对集合执行多种操作,这些集合在C#查询表达式中不可用,但方法调用支持这些集合,因此两种语法都值得一提。 For instance, Matt's query expression of:
例如,Matt的查询表达式为:
List<Foo> fooList = new List<Foo>();
IEnumerable<string> extract = from foo in fooList where foo.Bar > 10 select foo.Name.ToUpper();
is "pre-processed" into: 被“预处理”为:
List<Foo> fooList = new List<Foo>();
IEnumerable<string> extract = fooList.Where(foo => foo.Bar > 10)
.Select(foo => foo.Name.ToUpper());
If you want to (say) filter based on the index of the value in the original collection, you can use an appropriate overload of Where which is unavailable via query expressions: 如果要(说)基于原始集合中值的索引进行过滤,则可以使用查询表达式无法使用的适当的Where重载 :
List<Foo> fooList = new List<Foo>();
IEnumerable<string> extract = fooList.Where((foo, index) => foo.Bar > 10 + index)
.Select(foo => foo.Name.ToUpper());
Or you could find the length of the longest name matching the criteria: 或者,您可以找到符合条件的最长名称的长度:
List<Foo> fooList = new List<Foo>();
int longestName = fooList.Where((foo, index) => foo.Bar > 10 + index)
.Select(foo => foo.Name)
.Max();
(You don't have to do the projection and max in separate methods - there's a Max
overload which takes a projection as well.) (您不必做不同的方法投影和最大-有一个
Max
的过载,这需要投影为好。)
My point is that using extension methods you can very easily build up sophisticated queries. 我的观点是,使用扩展方法,您可以非常轻松地建立复杂的查询。
You mention Python generators as well - C# has this in the form of iterator blocks . 您还提到了Python生成器-C#以迭代器块的形式提供了此功能。 Indeed, these are incredibly useful when implementing LINQ-like operators.
确实,这些在实现类似LINQ的运算符时非常有用。 (Because most of LINQ to Objects is based on extension methods, you can add your own operators which look "native" to LINQ - although you can't change the query expression syntax yourself.)
(由于大多数LINQ to Objects都是基于扩展方法的,因此您可以添加自己的对LINQ看起来“本机”的运算符-尽管您不能自己更改查询表达式的语法。)
List<T>.ConvertAll
behaves just like list comprehensions by performing the same operation on every item on an existing list and then returning a new collection. List<T>.ConvertAll
行为类似于列表List<T>.ConvertAll
是对现有列表中的每个项目执行相同的操作,然后返回一个新集合。 This is an alternative to using Linq especially if you are still using .NET 2.0. 这是使用Linq的替代方法,特别是如果您仍在使用.NET 2.0。
In Python, a simple list comprehension example: 在Python中,一个简单的列表理解示例:
>>> foo = [1, 2, 3]
>>> bar = [x * 2 for x in foo]
>>> bar
[2, 4, 6]
For C# 3.0, you can pass a lambda function specifying what type of mapping function is needed. 对于C#3.0,您可以传递一个lambda函数,以指定需要哪种类型的映射函数。
public static void Main()
{
var foo = new List<int>{ 1, 2, 3};
var bar = foo.ConvertAll(x => x * 2); // list comprehension
foreach (var x in bar)
{
Console.WriteLine(x); // should print 2 4 6
}
}
For C# 2.0, you can use an anonymous method with the Converter
delegate to perform the equivalent. 对于C#2.0,您可以对
Converter
委托使用匿名方法来执行等效操作。
public static void Main()
{
List<int> foo = new List<int>(new int[]{ 1, 2, 3});
List<int> bar = foo.ConvertAll(new Converter<int, int>(delegate(int x){ return x * 2; })); // list comprehension
foreach (int x in bar)
{
Console.WriteLine(x); // should print 2 4 6
}
}
(Note: the same can be done with Arrays using Array.ConvertAll
(注意:使用
Array.ConvertAll
可以对数组执行相同操作
There's this: 有这个:
new List<FooBar> { new Foo(), new Bar() }
which is only a little longer than its python equivalent: 它只比它的python等长:
[Foo(), Bar()]
And then there is this: 然后是这样的:
public IEnumerable<FooBar> myFooBarGenerator() {
yield return new Foo();
yield return new Bar();
}
which is the python equivalent of: 相当于python的:
def myFooBarGenerator():
yield Foo()
yield Bar()
I know this is very very late an answer, but I too wondered if C# has anything equivalent to python's list comprehension. 我知道这是一个非常晚的答案,但我也想知道C#是否具有等同于python列表理解的功能。 Answers from both Matt Campbell and Jon Skeet show how to extract a list from an existing one, as far as I understood.
据我了解, Matt Campbell和Jon Skeet的答案都显示了如何从现有清单中提取清单。 But a python's list comprehension can also create a list from scratch.
但是python的列表理解也可以从头开始创建列表。 So here is what I came up with.
这就是我的想法。
First I will show the python list comprehension, and then its C# equivalent that I came up with. 首先,我将展示python列表理解,然后展示我想出的C#等效语言。
The toy task is to create a string like this 玩具的任务是创建一个像这样的字符串
cb01, cb02, cb02, ... , cb50
s = ', '.join('cb{0:02}'.format(i+1) for i in range(50))
string s = String.Join(", ", new Func<List<string>>( () =>
{
List<string> list = new List<string>();
foreach (int i in Enumerable.Range(1, 50))
list.Add(String.Format("cb{0:00}", i));
return list;
}).Invoke());
I am not sure if I over-did anything or not though. 我不确定我是否过量。
Edit: (from what Jon Skeet mentioned in his comment, a real one-liner equivalent to python's list comprehension) 编辑:(根据乔恩·斯基特在评论中提到的内容,这是等效于python列表推导的真正一句代码)
String.Join(", ", Enumerable.Range(1, 50).Select(x => $"cb{x:00}")))
Note that $
thing is a C# 6 feature . 请注意,
$
thing是C#6的功能 。 If you are still not using C# 6, you can go with the old String.Format()
way. 如果仍然不使用C#6,则可以使用旧的
String.Format()
方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.