Самая элегантная конструкция цикла?

Извините за новый вопрос. Я все еще изучаю программирование. Итак, я использую C++, и мне нужно сделать что-то вроде этого:

int n;
do {
    n = get_data();
    if (n != -1)
        send(n);
} while(n != -1);

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

Честно говоря, ваш код легко читается. Потратить время на то, чтобы сделать его короче (и дать больше времени, чтобы распаковать его в голове, когда вы снова прочтете его), - не лучшее вложение, которое вы можете сделать. Кому интересно: работает, работает эффективно и читается. Перейти к следующим строкам.

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

Ответы 10

Как насчет использования перерыв:

int n;
while(1) {
    n = get_data();
    if (n == -1)
        break;
    send(n);
}

Таким образом, вы тестируете только один раз и немедленно завершаете работу, если get_data не возвращает то, что вы хотите.

Я предпочитаю это, потому что это наиболее выразительно и масштабируется, даже когда get_data () становится более сложным. В этом случае я бы также добавил комментарий, описывающий условие выхода к «вечному циклу», например // прерывается, когда get_data () == -1.

peterchen 17.11.2008 02:58

Это экземпляр хорошо известной конструкции «Полтора цикла»: cs.duke.edu/~ola/patterns/plopd/loops.html#loop-and-a-half

Greg Hewgill 17.11.2008 03:10

Самая очевидная и, следовательно, самая элегантная, для меня она важна.

utku_karatas 17.11.2008 06:40
int n;
while (-1 != (n = get_data())) {
    send(n);
} // while

Я презираю, когда люди помещают константу в левой части сравнения.

SoapBox 17.11.2008 03:04

Некоторых из моих бывших коллег оскорбляет эта конструкция (побочный эффект, встроенный в условное выражение), и в нескольких учебниках говорится, что этого не следует делать. Я никогда не понимал почему - я думаю, что это нормально, но иногда лучше избегать по политическим причинам.

finnw 17.11.2008 03:04

Вы помещаете константу слева, так что это означает ошибку компилятора, когда вы случайно меняете == или! = На оператор присваивания (=). Это больше не проблема для большинства современных языков, особенно для современных IDE. Я до сих пор делаю это в коде C++.

Bill the Lizard 17.11.2008 03:18

Размещение константы в левой части выражения помогает избежать случайных ошибок, таких как if (n = -1)

Ed Marty 17.11.2008 03:18

Я удивлен, что никто не прокомментировал «// while» в конце такого короткого цикла.

TM. 17.11.2008 05:58

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

dreamlax 17.11.2008 05:59

Лично мне нравится -1 в правой части (немного легче читать (компилятор предупредит о назначении, и я компилирую с 0 предупреждениями)). У меня нет проблем с присваиванием в условиях, когда это делает код легко читаемым. В этой ситуации его читать намного легче, чем оригинал.

Martin York 17.11.2008 07:08

Цепляться за стандарты только потому, что это не уважительная причина. Первоочередная задача любого разработчика - поддержание кода. Все, что упрощает понимание (и, следовательно, поддержку) кода, отменяет большинство проблем.

Martin York 17.11.2008 07:10

Несмотря на состояние йоды, Джин мертв.

EvilTeach 25.03.2011 04:57

Ваша оригинальная версия в порядке.

В моей последней работе по программированию на C мы должны были следовать стандартам кодирования MISRA.

Согласно правилам MISRA это:

int n;
while(1) {
    n = get_data();
    if (n == -1)
        break;
    send(n);
}

запрещено из-за break, а это:

while((n = get_data()) != -1) { send(n); }

запрещено, потому что присваивание появляется в логическом контексте, поэтому я имею привычку писать циклы, аналогичные вашей исходной версии.

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

int n;
bool valid;
do {
    n = get_data();
    valid = n != -1;
    if (valid)
        send(n);
} while(valid);

Но для простого теста, такого как "n != -1", возможно, не стоит делать программу длиннее.

Я не смог найти онлайн-версию этого стандарта MISRA (хотя вы можете купить книгу за 25 долларов ...). Из вашего описания кажется глупым навязывать программисту громоздкий стиль кодирования.

Svante 18.11.2008 16:49

@Harleqin, вы правы, результирующий код может быть громоздким, некоторые правила избыточны, а некоторые другие не имеют смысла за пределами встроенных платформ.

finnw 19.11.2008 03:01

MISRA требует, чтобы код не был доступен только для записи. Его правила заключаются в том, чтобы сделать любую программу самоочевидной. Конечно, некоторые из них могут повысить производительность, но, как мы все знаем, оптимизацию следует производить после того, как у вас будет работающая программа. Если вы получаете четко читаемый код, вы позволяете другим использовать его повторно.

jpinto3912 21.11.2008 18:24

@ jpinto3912 - из этого примера кажется, что MISRA может иногда применять противоположное.

orip 09.12.2008 09:55

Подобно eed3si9n, но, возможно, легче читать:

 int n;
 while (n = get_data(), n != -1)
 {
     send(n);
 }

Придется возразить против облегчения чтения. Большинство программистов не понимают оператора запятой в C и натыкаются на конструкции такого типа.

JaredPar 17.11.2008 09:53

С другой стороны, многим программистам также трудно понять, что operator = возвращает присвоенное значение, и его использование может легко привести к ошибкам, упомянутым в другом месте. Но именно поэтому я сказал «возможно» вместо «определенно» :-)

SCFrench 17.11.2008 14:45

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

Brian 21.11.2008 16:48
for (int n = get_data(); n != -1; n = get_data()) {
  send(n);
}

Уберите фигурные скобки, если хотите сохранить строчку :)

Jonathan 21.11.2008 12:45

Да, если вы действительно хотите сделать его короче (чего я не делаю), это будет лучший способ. По крайней мере, умное использование цикла for.

e-satis 23.02.2010 02:47

Постройте с goto :)

int n;
goto inside; do {
  send(n);
inside:
  n=get_data();
} while(n!=-1);

Нет разницы между циклом do и циклом while, если вы никогда не вводите его сверху, не так ли? В противном случае я бы использовал более знакомую форму «пока».

finnw 19.11.2008 02:59

Да, вы правы, реальной разницы нет. Это дело личного вкуса :) Мне понравилась форма do-while, потому что строки с получением данных и строка с проверкой этих данных (условие цикла) располагаются одна за другой.

lazyden 19.11.2008 14:35

Обычно я бы проголосовал против, так как форматирование затрудняет чтение, но это интересный подход.

EvilTeach 25.03.2011 05:02
int get_data()
{
 ...
}

void _send(int )
{
 ...
}

int  send(int (*a) ())
{
   int n = a();

   if (n == -1)
      return n;

   _send(n);
   return 1;
}

int main()
{
  int (*fp)();
  fp = get_data;
  while ( send(fp)!= -1 );

  return 0;
}

HTH

int n;
n = get_data();
while (n != -1) {
  send(n);
  n = get_data();
}

Так учили делать петли в коболе еще тогда. Будет ли типичный компилятор скомпилировать это в эффективной форме? Из того, что я видел, решение lazydens обычно генерируется компилятором для повышения эффективности кеширования инструкций.

EvilTeach 25.03.2011 05:03

В Python вы бы сделали это:

while True:
    n = get_data()
    if n == -1:
        break
    send(n)

Как видите, это ненамного короче вашей версии C. Обычно код Python в 5-10 раз меньше, чем его эквивалент на C. Здесь дело обстоит не так, поэтому вы можете наслаждаться своим читаемым, достаточно коротким и быстрым сниппетом и сосредоточиться на чем-то другом.

Если вы хотите сделать его короче, проверьте ответ Джонатана, но на самом деле это не имеет значения.

/* This is cleaner */ 
AGAIN:;
    int n = get_data();
    if (n != -1)
    {
        send(n);
        goto AGAIN;
    }


/* This has some charm as well */ 
int n;
while ((n = get_data()) != -1)
    send(n);
/* and now i see that this is the top answer.  Oh well */ 

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