Могу ли я написать этот цикл for более компактным способом с помощью LINQ?

Есть ли способ очистить этот тип цикла с помощью LINQ? Я действительно думаю, что этот метод должен быть одним лайнером с LINQ. Но я не понимаю ..

Мой метод выглядит так:

int[] MakeList(int stepWidth)
{
    var ret = new List<int>();
    for (var i=0;i<360;i+=stepWidth)
    {
        ret.Add(i);
    }

    return ret.ToArray();
}

Единственное решение, которое я мог придумать, было:

Enumerable.Range(0, 360).Where(x => x % stepWidth == 0).ToArray();

Но этот Enumerabl.Range (0,360) мне кажется слишком грубым :)

Ответ - нет, и на самом деле не выше того, что у вас есть. и, кроме того, не бойтесь читабельного кода.

TheGeneral 31.10.2018 09:58

Не думаю, что ваше решение грубое. Он делает то, что вы хотите, и вам всегда будет нужен аспект stepWidth.

kaffekopp 31.10.2018 10:00

@TheGeneral: Я думаю, это зависит от того, что вы предпочитаете ... Мне очень нравится LINQ, и я думаю, что выражение linq будет быстрее читать, чем мой метод MakeList ..

richej 31.10.2018 10:00

Вы можете немного ускорить это. Enumerable.Range(0, 360 / stepWidth).Select(x => x * stepWidth).ToArray()

Dialecticus 31.10.2018 10:02

Я думаю, что это совершенно ясно и так, но если это то, что вы часто называете, его, безусловно, можно оптимизировать, чтобы он создавал только один массив, а не создавал список, а затем копировал содержимое этого списка в массив ...

Matthew Watson 31.10.2018 10:06

@Matthew Я посмотрел исходный код C#, и, очевидно, List<T> внутренне реализован как массив, и из ToArray() этот внутренний массив будет возвращен. Таким образом, нет окончательной копии, но все еще есть динамическое расширение массива, которое предотвращается, если мы создали массив сами.

Dialecticus 31.10.2018 10:10

@Dialecticus Нет, это совсем не так. Если бы это было так, изменение данных внутри массива, возвращаемого из ToArray(), также изменило бы данные в списке, чего не происходит (к счастью)!

Matthew Watson 31.10.2018 10:19

@ Мэтью, да, конечно. Я посмотрел на это снова, и новый массив создается из внутренней структуры Buffer. Кто знает, что я увидел впервые ..

Dialecticus 31.10.2018 10:30
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
8
77
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Комбинация .Select и .TakeWhile может быть одним из подходов, но он очень похож на другие подходы.

var result = Enumerable.Range(0, int.MaxValue)
                       .Select(i => i * step)
                       .TakeWhile(i => i < 360)
                       .ToArray();

По иронии судьбы, если вы подсчитаете все непробельные символы в подходе Linq, он на самом деле длиннее, чем код OP (а также труднее читать, IMO).

Matthew Watson 31.10.2018 10:26

@MatthewWatson, я думаю (IMO :)), TakeWhile более информативен в отношении намерений, и даже дольше он будет повторять только необходимое количество раз, где Where будет повторять все числа в пределах диапазона.

Fabio 31.10.2018 10:57

Во-первых: ваш код приятный и читабельный.

Второе: не бойтесь циклов - циклы отлично показывают замыслы программиста. Если бы мне пришлось что-то изменить, я бы исключил List<i>:

int[] MakeList(int stepWidth)
{
    var length = (360 + stepWidth - 1) / stepWidth;
    var ret = new int[length];
    for (var i = 0; i < length; i++)
    {
        ret[i] = i * stepWidth;
    }

    return ret;
}

В-третьих: если LINQ используется часто, я бы вернул IEnumerable<int> (см. Генераторы):

IEnumerable<int> MakeSequence(int step)
{
    for (var i = 0; i < 360; i += step)
        yield return i;
}

И используйте его так: MakeSequence(x).ToArray() или MakeSequence(x).[SomeLinqMethods].

На самом деле это не возвращает правильный результат для некоторых значений stepWidth. Например, попробуйте это с stepWidth ==7 и сравните с результатами OP. Он вернет на одно значение меньше. Фактическое количество нужно округлить, например (360 + stepWidth - 1) / stepWidth.

Matthew Watson 31.10.2018 10:30

Спасибо, Мэттью, ты прав. Исправленный. Генератор проверил, работает как положено.

Paweł Dyl 31.10.2018 11:02

Другие вопросы по теме