代码之家  ›  专栏  ›  技术社区  ›  minty

C有什么可以与Python的列表理解相比较的吗?

  •  17
  • minty  · 技术社区  · 17 年前

    我想用C生成一个列表。我错过了python的列表理解。有没有一种C方法可以像列表理解或生成器表达式那样动态地创建集合?

    5 回复  |  直到 9 年前
        1
  •  20
  •   Jon Skeet    17 年前

    如果您使用的是C 3.0(VS2008),那么linq to对象可以执行非常类似的操作:

    List<Foo> fooList = new List<Foo>();
    IEnumerable<Foo> extract = from foo in fooList where foo.Bar > 10 select Foo.Name.ToUpper();
    
        2
  •  14
  •   Community Mohan Dere    9 年前

    Matt提到了查询表达式。顺便说一句,它们一般可用于LINQ,而不仅仅是对象的LINQ。(例如,应用于Linq to SQL DataContext的同一查询将在数据库上执行筛选和投影。)

    尽管查询表达式通常最终会调用 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 通过查询表达式不可用:

    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的形式是 iterator blocks . 实际上,这些在实现类LINQ操作符时非常有用。(因为大多数linq to对象都基于扩展方法,所以您可以添加自己的操作符,这些操作符看起来像linq的“本机”操作符,尽管您自己不能更改查询表达式语法。)

        3
  •  5
  •   Ray    16 年前

    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

        4
  •  1
  •   Sнаđошƒаӽ    9 年前

    有这样的:

    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()
    
        5
  •  0
  •   Community Mohan Dere    9 年前

    我知道这是一个非常晚的答案,但我也很想知道C是否有类似于Python列表理解的东西。两者的答案 Matt Campbell Jon Skeet 展示如何 提取液 据我所知,是另一份现有清单。但是,Python的列表理解也可以从头开始创建列表。这就是我的想法。

    首先,我将展示python列表的理解,然后是我想出的C等价物。

    玩具的任务是创建这样的字符串

    cb01, cb02, cb02, ... , cb50
    

    python列表理解:

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

    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());
    

    不过,我不确定我是否做得过火了。


    编辑: (从乔恩·斯基特在他的评论中提到的,一个真正的一行程序,相当于python的列表理解)

    String.Join(", ", Enumerable.Range(1, 50).Select(x => $"cb{x:00}")))
    

    注意 $ 事情是 C# 6 feature . 如果你仍然不使用C 6,你可以使用旧的 String.Format() 方式。