Подтвердить что ты не робот

Имеет ли С# что-либо сопоставимое с пониманием списка Python?

Я хочу создать список на С#. Мне не хватает понятий в списках python. Есть ли способ С# для создания коллекций "на лету", например, в виде списков или выражений генератора в python?

4b9b3361

Ответ 1

Если вы используете С# 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();

Ответ 2

Мэтт упомянул выражения запроса. Они доступны для LINQ в общем, кстати, а не только LINQ to Objects. (Например, тот же запрос, примененный к LINQ to SQL datacontext, будет выполнять фильтр и проекцию в базе данных.)

Выражения запроса в С# 3 - это просто синтаксический сахар над написанием нормального кода С#, хотя выражения запроса обычно заканчиваются вызовом методов . (Им это не нужно, и компилятору все равно, но они обычно это делают.) Существуют различные вещи, которые вы можете делать с коллекциями, которые недоступны в выражениях запросов С#, но которые поддерживаются вызовами методов, поэтому стоит осознавать оба вида синтаксиса. Например, выражение запроса 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());

Если вы хотите (скажем) фильтр на основе индекса значения в исходной коллекции, вы можете использовать соответствующую перегрузку 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 - С# имеет это в виде блоков iterator. Действительно, они невероятно полезны при реализации LINQ-подобных операторов. (Поскольку большинство LINQ to Objects основаны на методах расширения, вы можете добавить своих собственных операторов, которые выглядят "родными" для LINQ, хотя вы не можете самостоятельно изменить синтаксис выражения запроса.)

Ответ 3

List<T>.ConvertAll ведет себя точно так же, как понимание списков, выполняя ту же операцию для каждого элемента в существующем списке и затем возвращая новую коллекцию. Это альтернатива использованию Linq, особенно если вы все еще используете .NET 2.0.

В Python используется простой пример понимания списка:

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

Для С# 3.0 вы можете передать функцию лямбда, указав, какой тип функции сопоставления необходим.

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

Для С# 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

Вот это:

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

который немного меньше, чем его эквивалент python:

[Foo(), Bar()]

И тогда есть следующее:

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

который является эквивалентом питона:

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

Ответ 5

Я знаю, что это очень поздний ответ, но я тоже задавался вопросом, имеет ли С# что-либо, эквивалентное пониманию списка python. Ответы Matt Campbell и Jon Skeet показывают, как извлечь список из другого существующего, насколько это возможно Я понял. Но понимание списка python также может создавать список с нуля. Итак, вот что я придумал.

Сначала я покажу вам понимание списка python, а затем его эквивалент С#, с которым я столкнулся.

Задача игрушка состоит в том, чтобы создать строку, подобную этой

cb01, cb02, cb02, ... , cb50

Понимание списка Python:

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

Я не уверен, что я сделал что-то или нет, хотя.


Изменить: (из того, что упоминал Джон Скит в своем комментарии, настоящий однострочный эквивалент для понимания списка python)

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

Обратите внимание, что $ вещь - функция С# 6. Если вы все еще не используете С# 6, вы можете пойти со старым способом String.Format().