Скажите, что у вас есть DataFrame
:
>>> df = pd.DataFrame([['hello', 'hello world'], ['abcd', 'defg']], columns=['a','b'])
>>> df
a b
0 hello hello world
1 abcd defg
Вы всегда можете использовать оператор in
в выражении лямбда для создания вашего фильтра.
>>> df.apply(lambda x: x['a'] in x['b'], axis=1)
0 True
1 False
dtype: bool
Трюк здесь состоит в том, чтобы использовать опцию axis=1
в apply
для передачи элементов в функцию лямбда по строке, в отличие от столбца по столбцу.
Вы можете break
выйти из do{...}while(false)
.
Это изобретательный способ эмулировать GOTO
, поскольку эти два практически идентичны:
// NOTE: This is discouraged!
do {
if (someCondition) break;
// some code be here
} while (false);
// more code be here
и:
// NOTE: This is discouraged, too!
if (someCondition) goto marker;
// some code be here
marker:
// more code be here
С другой стороны, обе эти должно действительно выполняться с помощью if
s:
if (!someCondition) {
// some code be here
}
// more code be here
Хотя вложенность может стать немного уродливой, если вы просто превратите длинную строку forward- GOTO
s в вложенные if
s. Настоящий ответ - правильный рефакторинг, хотя и не имитирующий архаичные языковые конструкции.
Если вы отчаянно пытались транслировать алгоритм с GOTO
s в нем, вы могли бы, вероятно, сделать это с этой идиомой. Это, конечно, нестандартный и хороший показатель того, что вы не придерживаетесь близко ожидаемых идиом языка.
Я не знаю ни одного языка C, где do / while является идиоматическое решение для чего угодно.
Вероятно, вы могли бы реорганизовать весь беспорядок во что-то более разумное, чтобы сделать его более идиоматичным и более читаемым.
continue
в конце, как я показал. В undefined
я просто хочу сказать, что вы не знаете, работает ли он более одного раза, если вы не можете предсказать, будут ли условия выполняться на определенной итерации. Без каких-либо continue
s в нем do..while(false)
будет выполняться один раз, но также без каких-либо break
s в нем while(true)
будет работать вечно, поэтому «поведение по умолчанию» на самом деле не имеет отношения к пониманию того, что может i> сделать с помощью циклов.
– Alan Plum
23 February 2010 в 12:32
Это просто: Очевидно, вы можете выпрыгнуть из фальшивого цикла в любое время, используя инструкцию break
. Кроме того, блок do
представляет собой отдельную область (которая также может быть достигнута только с помощью { ... }
).
В такой ситуации может быть лучше использовать RAII (объекты автоматически разрушаются правильно когда функция заканчивается). Другая аналогичная конструкция - использование goto
- да, я знаю, что это зло , но его можно использовать для общего кода очистки следующим образом:
<return-type> function(<params>)
{
<initialization>
<main code for function using "goto error;" if something goes wrong>
<tidy-up in success case & return>
error:
<commmon tidy-up actions for error case & return error code or throw exception>
}
(As В стороне: конструктор do-while-false используется в Lua, чтобы найти недостающую инструкцию continue
.)
Этот трюк используется программистами, которые слишком застенчивы, чтобы использовать явный goto
в своем коде. Автор вышеуказанного кода хотел иметь возможность перейти непосредственно к точке «очистка и возврат» из середины кода. Но они не хотели использовать метку и явные goto
. Вместо этого они могут использовать break
внутри тела вышеупомянутого «поддельного» цикла для достижения того же эффекта.
Многие люди отмечают, что он часто используется с перерывом как неудобный способ написания «goto». Это, вероятно, так, если оно написано непосредственно в функции.
В макросе OTOH, do {something; } while (false) - это удобный способ FORCE с запятой после вызова макроса, абсолютно никакой другой токен не может следовать.
И еще одна возможность заключается в том, что там либо был цикл, либо ожидалась итерация который должен быть добавлен в будущем (например, в тестовой версии, итерация не нужна для прохождения тестов, но логически было бы целесообразно зацикливать там, если функция должна быть несколько более общей, чем требуется в настоящее время)
Я видел такой код, поэтому вы можете использовать break
как goto
.
Я видел, что он использовался как полезный шаблон, когда есть много потенциальных точек выхода для функции, но тот же код очистки всегда требуется независимо от того, как функция выходит.
Это может сделать утомительно, если / else - если дерево намного легче читать, просто нужно ломаться всякий раз, когда достигается точка выхода, а остальная часть логической строки впоследствии.
Этот шаблон также полезен на языках, которые У меня есть инструкция goto. Возможно, именно там исходный программист узнал образец.
В дополнение к уже упомянутым «примерам goto», do ... while (0) idiom иногда используется в определении макроса, чтобы обеспечить скобки в определении и все еще иметь работу компилятора с добавлением полуколонки к конец макросообщения.
Некоторые кодеры предпочитают иметь только один выход / возврат из своих функций. Использование манекена do {....} while (false); позволяет вам «вырваться» из фиктивной петли, как только вы закончите, и все еще имеете один возврат.
Я java-кодер, поэтому мой пример будет похож на
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class p45
{
static List<String> cakeNames = Arrays.asList("schwarzwald torte", "princess", "icecream");
static Set<Integer> forbidden = Stream.of(0, 2).collect(Collectors.toSet());
public static void main(String[] argv)
{
for (int i = 0; i < 4; i++)
{
System.out.println(String.format("cake(%d)=\"%s\"", i, describeCake(i)));
}
}
static String describeCake(int typeOfCake)
{
String result = "unknown";
do {
// ensure type of cake is valid
if (typeOfCake < 0 || typeOfCake >= cakeNames.size()) break;
if (forbidden.contains(typeOfCake)) {
result = "not for you!!";
break;
}
result = cakeNames.get(typeOfCake);
} while (false);
return result;
}
}
Это очень распространенная практика. В C. Я пытаюсь думать об этом так, как будто вы хотите лгать себе таким образом: «Я не использую goto
». Думая об этом, не было бы ничего плохого в использовании goto
, используемого аналогичным образом. Фактически это также уменьшит уровень отступов.
Тем не менее, я заметил, что очень часто эта петля do..while
имеет тенденцию к росту. И затем они получают внутри if
s и else
, что делает код на самом деле не очень читаемым, не говоря уже о проверке.
Те, кто do..while
, как правило, предназначены для очистки . По возможности я предпочел бы использовать RAII и вернуться раньше из функции short . С другой стороны, C не предоставляет вам столько удобств, как C ++, что делает do..while
одним из лучших подходов к очистке.
Это забавно. Вероятно, в петле есть перерывы, как говорили другие. Я бы сделал это так:
while(true)
{
<main code for function>
break; // at the end.
}
do..while(false)
всегда выходит, while(true)
находится на рискованной стороне.
– Dmitry
22 February 2010 в 22:44
while(true)
- правильная идиома на большинстве языков. Вы часто найдете его в графических приложениях в качестве основного цикла программы. Поскольку вы в основном предполагаете, что программа не должна умирать, пока не будет сказано, что это do..while(false)
вызовет всевозможные надуманные логики. Этот подход может быть более рискованным из перфекционистского POV, но он семантически проще и, следовательно, менее подвержен ошибкам для программистов-программистов (извините, Скайнет).
– Alan Plum
22 February 2010 в 23:30
do{...}while(false)
точно такой же, как while(true){ .. break;}
– N 1.1
10 March 2010 в 10:18
Возможно, он используется так, чтобы break
можно было использовать внутри, чтобы прервать выполнение дополнительного кода в любой точке:
do {
if (!condition1) break;
some_code;
if (!condition2) break;
some_further_code;
// …
} while(false);
goto
только потому, что кто-то слышал, что это «плохо».
– Anon.
22 February 2010 в 21:55
Перерыв как goto, вероятно, является ответом, но я выдвину еще одну идею.
Возможно, он хотел иметь локально определенные переменные и использовал эту конструкцию для получения новой области.
Помните, что в последнее время C ++ допускает {...}
в любом месте, это не всегда так.
{...}
где-то более современная разработка в C ++ (помните, что первый C ++, который я использовал, был реализован с предварительным процессором, и это не позволяло это современное использование .) Возможно, автор был просто старой школой.
– Hogan
22 February 2010 в 23:21
Я думаю, что это делается для использования операторов break
или continue
. Некоторая логика кода «goto».
Это просто извращение while
, чтобы получить семантику goto tidy-up
без использования слова goto.
Это плохая форма, потому что, когда вы используете другие петли внутри внешнего while
, breaks
становятся двусмысленными для читателя. «Предполагается ли это, что он должен выйти?» или это предназначено только для выхода из внутреннего цикла? »
Я работаю с Adobe InDesign SDK, а примеры InDesign SDK имеют почти каждую функцию, написанную так. Это связано с тем, что функция обычно очень длинная. Где вам нужно выполнить QueryInterface (...), чтобы получить что-либо из объектной модели приложения. Таким образом, обычно каждый QueryInterface следует за if
, но не прошел хорошо, перерыв.
Многие уже заявили о сходстве между этой конструкцией и goto
и выразили предпочтение goto. Возможно, фон этого человека включал среду, в которой goto's строго запрещалось правилами кодирования?
Многие ответчики дали объяснение do{(...)break;}while(false)
. Я хотел бы дополнить эту картину еще одним примером реальной жизни.
В следующем коде мне пришлось установить перечислитель operation
на основе адреса, на который указывает указатель data
. Поскольку ящик коммутатора может использоваться только для скалярных типов, я сначала сделал это неэффективно
if (data == &array[o1])
operation = O1;
else if (data == &array[o2])
operation = O2;
else if (data == &array[on])
operation = ON;
Log("operation:",operation);
Но поскольку Log () и остальная часть кода повторяются для любого выбранного значения операции, я блуждал, как чтобы пропустить остальные сравнения, когда адрес уже обнаружен. И вот здесь do{(...)break;}while(false)
пригодится.
do {
if (data == &array[o1]) {
operation = O1;
break;
}
if (data == &array[o2]) {
operation = O2;
break;
}
if (data == &array[on]) {
operation = ON;
break;
}
} while (false);
Log("operation:",operation);
Можно задаться вопросом, почему он не мог сделать то же самое с break
в выражении if
, например:
if (data == &array[o1])
{
operation = O1;
break;
}
else if (...)
break
взаимодействует исключительно с ближайшим замкнутым контуром или переключателем, будь то тип for
, while
или do .. while
, поэтому, к сожалению, это не сработает.
Другая причина, по которой я могу думать, заключается в том, что она украшает фигурные скобки , в то время как я верю в более новые стандартные фигуры C ++, голые скобки не в порядке (ISO C им не нравится). В противном случае, чтобы успокоить статический анализатор, например, lint.
Не знаете, почему вы хотите их, возможно, переменную область или преимущество с отладчиком.
См. Trivial Do While loop и Скобки хороши из C2.
Чтобы прояснить мою терминологию (которая, как я полагаю, следует за стандартным использованием):
Naked :
init();
...
{
c = NULL;
mkwidget(&c);
finishwidget(&c);
}
shutdown();
Пустые фигурные скобки (NOP):
{}
например
while (1)
{} /* Do nothing, endless loop */
Блок :
if (finished)
{
closewindows(&windows);
freememory(&cache);
}
, который станет
if (finished)
closewindows(&windows);
freememory(&cache);
, если фигурные скобки будут удалены, что изменит поток выполнения, а не только область локальных переменных. Таким образом, не «автономный» или «голый».
Голые фигурные скобки или блок могут использоваться для обозначения любого раздела кода, который может быть потенциальным (встроенной) функцией, которую вы хотите отметить, но не рефактору в то время.
Он похож на программиста C. В C ++ у автоматических переменных есть деструкторы, которые вы используете для очистки, поэтому перед возвратом не должно быть ничего необходимого. В C у вас не было этой RAII идиомы, поэтому, если у вас есть общий код очистки, вы либо goto
, либо используете однократный цикл, как указано выше.
. Его главный недостаток по сравнению с идиомой C ++ заключается в том, что он не будет убирать, если в тело будет выброшено исключение. У C не было исключений, поэтому это не было проблемой, но это делает его плохой привычкой в C ++.
Я думаю, что удобнее писать break
вместо goto end
. Вам даже не нужно придумывать имя для ярлыка, которое делает намерение более ясным: вы не хотите переходить на метку с определенным именем. Вы хотите выбраться отсюда.
Также, возможно, вам понадобятся брекеты. Итак, это версия do{...}while(false);
:
do {
// code
if (condition) break; // or continue
// more code
} while(false);
И так вы должны были бы выразить это, если хотите использовать goto
:
{
// code
if (condition) goto end;
// more code
}
end:
I думаю, смысл первой версии гораздо легче понять. Также легче писать, проще расширять, проще переводить на язык, который не поддерживает goto
и т. Д.
Наиболее часто упоминаемая проблема использования break
что это плохо замаскировано goto
. Но на самом деле break
имеет больше сходства с return
: обе команды выпрыгивают из блока кода, который в значительной степени структурирован по сравнению с goto
. Тем не менее обе команды позволяют нескольким точкам выхода в блоке кода, который иногда может сбивать с толку. В конце концов, я попытался бы найти наиболее четкое решение, независимо от того, что находится в конкретной ситуации.
do{ ... }while(false);
в целом. Но на самом деле речь идет о том, чтобы использовать его для эмуляции какого-то try{ ... }finally{ ... }
.
– Robert
19 June 2012 в 14:14
Я согласен с большинством плакатов об использовании в качестве тонко замаскированного goto. Макросы также упоминаются как потенциальная мотивация для написания кода в стиле.
Я также видел эту конструкцию, используемую в смешанных средах C / C ++ как исключение бедных. «Do {} while (false)» с «break» можно использовать для перехода в конец блока кода, если в цикле будет встречено что-то, что обычно требует исключения.
Я также использовал эту конструкцию, используемую в магазинах, где применяется идеология «единственного возвращения на каждую функцию». Опять же, это вместо явного «goto», но мотивация заключается в том, чтобы избежать множественных точек возврата, а не «пропустить» код и продолжить фактическое выполнение внутри этой функции.
Сколько лет был автор?
Я спрашиваю, потому что однажды я наткнулся на какой-то код Fortran в реальном времени, который сделал это, еще в конце 80-х. Оказывается, это действительно хороший способ имитировать потоки на ОС, которые их не имеют. Вы просто помещаете всю программу (ваш планировщик) в цикл и называете свои «потоковые» подпрограммы «один за другим». Процедуры потоков сами по себе являются циклами, которые повторяются до тех пор, пока не произойдет один из нескольких условий (часто один из них является определенным количеством прошло время). Это «совместная многозадачность», так как отдельные потоки позволяют отказываться от процессора каждый раз, а затем, чтобы другие не истощались. Вы можете вставлять вызовы подпрограмм цикла для имитации приоритета потока полосы.
Несколько объяснений. Первый - общий, второй - для макросов препроцессора C с параметрами:
Я видел, что это используется в простом C-коде. В принципе, это более безопасная версия goto, так как вы можете вырваться из нее, и вся память очищается должным образом.
Почему что-то goto
-подобно быть хорошим? Ну, если у вас есть код, в котором почти каждая строка может возвращать ошибку, но вам нужно реагировать на все одинаково (например, передав ошибку вашему вызывающему абоненту после очистки), обычно более читаемо, чтобы избежать if( error ) { /* cleanup and error string generation and return here */ }
, поскольку он избегает дублирования кода очистки.
Однако в C ++ у вас есть исключения + RAII для этой цели, поэтому я бы назвал это неправильным стилем кодирования.
Если вы забыли точку с запятой после функционального вызова макроса, аргументы могут быть сжаты нежелательным образом и скомпилированы в действительный синтаксис. Представьте себе макрос
#define PRINT_IF_DEBUGMODE_ON(msg) if( gDebugModeOn ) printf("foo");
. Это случайно называется
if( foo )
PRINT_IF_DEBUGMODE_ON("Hullo\n")
else
doSomethingElse();
. «Else» будет считаться связанным с gDebugModeOn
, поэтому, когда foo
false
, точный реверс того, что предназначалось, будет иметь место.
Так как do / while имеет фигурные скобки, временные переменные имеют четко определенные область действия, с которой они не могут убежать.
Некоторые макросы активируются только в отладочных сборках. Вы определяете их как:
#if DEBUG
#define DBG_PRINT_NUM(n) printf("%d\n",n);
#else
#define DBG_PRINT_NUM(n)
#endif
Теперь, если вы используете это в сборке релизов внутри условного выражения, он компилируется в
if( foo )
;
. Многие компиляторы видят это как то же, что
if( foo );
, который часто записывается случайно. Поэтому вы получаете предупреждение. Do {} while (false) скрывает это от компилятора и принимается им как указание на то, что вы действительно ничего не хотите здесь делать.
Макрос из предыдущего примера:
if( foo )
DBG_PRINT_NUM(42)
doSomething();
Теперь, в сборке отладки, поскольку мы также обычно включаем точку с запятой, это компилируется просто отлично. Однако в релиз-сборке это внезапно превращается в:
if( foo )
doSomething();
Или более четко отформатировано
if( foo )
doSomething();
Это совсем не то, что было предназначено. Добавление do {...} while (false) вокруг макроса превращает недостающую точку с запятой в ошибку компиляции.
В общем, вы хотите использовать исключения в C ++ для обработки ошибок и шаблоны вместо макросов. Однако в очень редком случае, когда вам все еще нужны макросы (например, при генерации имен классов с использованием вставки меток) или они ограничены равным C, это полезный шаблон.
x =1; y = 2; { int tmp = y; y = x; x = tmp; }
.
– chepner
24 August 2017 в 12:16
#define DBG_PRINT_NUM(n) {}
.
– chepner
6 September 2017 в 16:25
if(a) DBG_PRINT_NUM(n); else other();
, он не будет компилироваться. Только if(a) {} else other();
или if(a) ; else other();
действительны, но if(a) {}; else other();
нет, потому что это делает «если», состоит из двух утверждений.
– uliwitness
8 September 2017 в 13:23