简体   繁体   English

C#是否具有与Python的列表推导相当的功能?

[英]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 CampbellJon 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

Python list comprehension: Python列表理解:

s = ', '.join('cb{0:02}'.format(i+1) for i in range(50))

C# equivalent I came up with: 我想出了等效的C#:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM