C#有没有与Python的列表推导相媲美的东西?

时间:2008-11-27 05:55:24

标签: c# python list list-comprehension

我想在C#中生成一个列表。我错过了python的列表推导。是否有一种C#方式可以动态创建集合,例如列表推导或生成器表达式在python中做什么?

4 个答案:

答案 0 :(得分:22)

如果您使用的是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();

答案 1 :(得分:15)

马特提到了查询表达式。顺便说一下,这些可用于LINQ - 不仅仅是LINQ to Objects。 (例如,应用于LINQ to SQL datacontext的相同查询将执行数据库上的过滤器和投影。)

C#3中的查询表达式只是编写普通C#代码的语法糖 - 尽管查询表达式通常最终会调用extension methods。 (他们没有,并且编译器并不关心,但他们通常会这样做。)对于C#查询表达式中不可用但是方法调用支持的集合,可以执行各种操作,因此值得了解这两种语法。例如,Matt的查询表达式为:

List<Foo> fooList = new List<Foo>();
IEnumerable<string> extract = from foo in fooList where foo.Bar > 10 select foo.Name.ToUpper();

被“预处理”成:

List<Foo> fooList = new List<Foo>();
IEnumerable<string> extract = fooList.Where(foo => foo.Bar > 10)
                                     .Select(foo => foo.Name.ToUpper());

如果您希望(比方说)根据原始集合中的值索引进行过滤,则可以使用appropriate overload of Where,该iterator blocks通过查询表达式不可用:

List<Foo> fooList = new List<Foo>();
IEnumerable<string> extract = fooList.Where((foo, index) => foo.Bar > 10 + index)
                                     .Select(foo => foo.Name.ToUpper());

或者您可以找到符合条件的最长名称的长度:

List<Foo> fooList = new List<Foo>();
int longestName = fooList.Where((foo, index) => foo.Bar > 10 + index)
                         .Select(foo => foo.Name)
                         .Max();

(你没有在单独的方法中进行投影和最大值 - 有一个Max重载也需要投影。)

我的观点是,使用扩展方法可以非常轻松地构建复杂的查询。

你也提到了Python生成器--C#以{{3}}的形式提供了这个。实际上,这些在实现类似LINQ的运算符时非常有用。 (因为LINQ to Objects的大多数都是基于扩展方法,所以你可以添加自己看起来像LINQ“本机”的运算符 - 虽然你不能自己更改查询表达式语法。)

答案 2 :(得分:5)

List<T>.ConvertAll的行为与列表推导类似,方法是对现有列表中的每个项执行相同的操作,然后返回新的集合。这是使用Linq的替代方法,特别是如果您仍在使用.NET 2.0。

在Python中,一个简单的列表理解示例:

>>> foo = [1, 2, 3]
>>> bar = [x * 2 for x in foo]
>>> bar
[2, 4, 6]

对于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
    }
}

对于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
    }
}

(注意:使用Array.ConvertAll

可以使用数组完成相同的操作

答案 3 :(得分:1)

就是这样:

new List<FooBar> { new Foo(), new Bar() }

只比它的python等价物长一点:

[Foo(), Bar()]

然后有这个:

public IEnumerable<FooBar> myFooBarGenerator() {
     yield return new Foo();
     yield return new Bar();
}

是python的等价物:

def myFooBarGenerator():
    yield Foo()
    yield Bar()