Это наиболее популярный способ (мне кажется) проверки, находится ли значение в массиве:
for (int x : array)
{
if (x == value)
return true;
}
return false;
Однако в книге, которую я читал много лет назад, вероятно, Виртом или Дейкстрой, было сказано, что этот стиль лучше (по сравнению с циклом while с выходом внутри):
int i = 0;
while (i < array.length && array[i] != value)
i++;
return i < array.length;
Таким образом, дополнительное условие выхода становится явной частью инварианта цикла, в цикле нет скрытых условий и выходов, все становится более очевидным и более структурированным. Я обычно предпочитал этот последний шаблон всякий раз, когда это было возможно, и использовал for
-loop только для итерации от a
до b
.
И все же я не могу сказать, что первая версия менее ясна. Может быть, это еще яснее и проще для понимания, по крайней мере, для начинающих. Так что я все еще задаю себе вопрос, какой из них лучше?
Может быть, кто-то может дать хорошее обоснование в пользу одного из методов?
Обновление: это не вопрос множественных точек возврата функции, лямбда-выражения или поиска элемента в массиве как такового. Речь идет о том, как писать циклы с более сложными инвариантами, чем одно неравенство.
Обновление: хорошо, я вижу точку зрения людей, которые отвечают и комментируют: я смешал здесь цикл foreach, который сам по себе уже гораздо более понятен и читаем, чем цикл while. Я не должен был этого делать. Но это также интересный вопрос, поэтому давайте оставим его как есть: цикл foreach и дополнительное условие внутри, или цикл while с явным инвариантом цикла и постусловием после. Кажется, что цикл foreach с условием и выходом / разрывом выигрывает. Я создам дополнительный вопрос без цикла foreach (для связанного списка).
источник
collection.contains(foo)
Ответы:
Я думаю, что для простых циклов, таких как эти, стандартный первый синтаксис намного яснее. Некоторые люди считают, что многократные возвраты сбивают с толку или запах кода, но для небольшого фрагмента кода я не верю, что это реальная проблема.
Это становится немного более спорным для более сложных циклов. Если содержимое цикла не помещается на вашем экране и имеет несколько возвратов в цикле, необходимо сделать аргумент, что несколько точек выхода могут усложнить поддержку кода. Например, если вы должны были убедиться, что какой-либо метод поддержания состояния выполнялся до выхода из функции, было бы легко пропустить добавление его в один из операторов return, и вы могли бы вызвать ошибку. Если все конечные условия можно проверить в цикле while, у вас есть только одна точка выхода, и вы можете добавить этот код после нее.
Тем не менее, с помощью циклов особенно полезно попытаться использовать как можно больше логики в отдельных методах. Это позволяет избежать многих случаев, когда второй метод будет иметь преимущества. Скудные циклы с четко разделенной логикой будут иметь большее значение, чем какой из этих стилей вы используете. Кроме того, если большая часть кода вашего приложения использует один стиль, вам следует придерживаться этого стиля.
источник
Это легко.
Почти ничего не значит больше, чем ясность для читателя. Первый вариант мне показался невероятно простым и понятным.
Вторую «улучшенную» версию мне пришлось прочитать несколько раз и убедиться, что все граничные условия были правильными.
Есть ZERO DOUBT, который является лучшим стилем кодирования (первый намного лучше).
Теперь - то, что ЯСНО для людей, может варьироваться от человека к человеку. Я не уверен, что существуют какие-либо объективные стандарты для этого (хотя публикация на таком форуме и получение информации от различных людей может помочь).
В этом конкретном случае, однако, я могу сказать вам, почему первый алгоритм более понятен: я знаю, как выглядит и делает итерация C ++ по синтаксису контейнера. Я усвоил это. Кто-то UNFAMILIAR (его новый синтаксис) с таким синтаксисом может предпочесть второй вариант.
Но как только вы знаете и понимаете этот новый синтаксис, его базовая концепция, которую вы можете просто использовать. При использовании итерационного цикла (второго) вы должны тщательно проверить, что пользователь ПРАВИЛЬНО проверяет все граничные условия для цикла по всему массиву (например, меньше, чем вместо «меньше или равно», тот же индекс, используемый для теста и для индексации и т. д.).
источник
longerLength = true
, затемreturn longerLength
.length
. Если бы он был фактически объявлен как массив, а не как указатель, они могли бы использоватьsizeof
или, если это было быstd::array
, правильная функция-членsize()
,length
свойства не существует .sizeof
будет в байтах ... Самый общий с C ++ 17std::size()
.Не совсем. Переменная
i
существует вне цикла , а здесь и является , таким образом , часть внешней области, в то время как (каламбур)x
изfor
-loop существует только в пределах цикла. Область применения - один из очень важных способов представить структуру в программировании.источник
Два цикла имеют разную семантику:
Первый цикл просто отвечает на простой вопрос «да / нет»: «Содержит ли массив искомый объект?» Это делается максимально кратко.
Второй цикл отвечает на вопрос: «Если массив содержит искомый объект, каков индекс первого совпадения?» Опять же, это делается максимально кратко.
Так как ответ на второй вопрос содержит строго больше информации, чем ответ на первый, вы можете выбрать ответ на второй вопрос и затем получить ответ на первый вопрос. Это то, что линия
return i < array.length;
делает , в любом случае.Я считаю, что обычно лучше всего использовать инструмент, который соответствует цели, если вы не можете повторно использовать уже существующий, более гибкий инструмент. То есть:
bool
переменную и разрыв, тоже хорошо. (Избегает второгоreturn
утверждения, ответ доступен в переменной вместо возврата функции.)std::find
в порядке (повторное использование кода!).bool
нет.источник
Я предложу третий вариант в целом:
Существует много разных причин для перебора массива: проверьте, существует ли определенное значение, преобразуйте массив в другой массив, вычислите совокупное значение, отфильтруйте некоторые значения из массива ... Если вы используете обычный цикл for, неясно кратко о том, как используется цикл for. Тем не менее, большинство современных языков имеют богатые API в своих структурах данных массива, которые делают эти различные намерения очень явными.
Сравните преобразование одного массива в другой с помощью цикла for:
и используя функцию в стиле JavaScript
map
:Или суммирование массива:
против:
Сколько времени вам нужно, чтобы понять, что это делает?
против
Во всех трех случаях, хотя цикл for определенно читабелен, вам нужно потратить несколько минут, чтобы выяснить, как используется цикл for, и проверить правильность всех счетчиков и условий выхода. Современные функции лямбда-стиля делают цели циклов чрезвычайно явными, и вы точно знаете, что вызываемые функции API реализованы правильно.
Большинство современных языков, включая JavaScript , Ruby , C # и Java , используют этот стиль функционального взаимодействия с массивами и подобными коллекциями.
В целом, хотя я не думаю, что использование циклов for обязательно является неправильным, и это вопрос личного вкуса, я решительно предпочел использовать этот стиль работы с массивами. Это в частности из-за повышенной ясности в определении того, что делает каждый цикл. Если ваш язык имеет аналогичные функции или инструменты в своих стандартных библиотеках, я предлагаю вам также рассмотреть возможность применения этого стиля!
источник
array.find
напрашивается на вопрос, так как мы должны обсудить наилучший способ реализацииarray.find
. Если вы не используете аппаратное обеспечение со встроеннойfind
операцией, мы должны написать цикл там.find
в их стандартных библиотеках. Несомненно, эти библиотеки реализуютfind
и используют его род для циклов, но это то, что делает хорошая функция: она абстрагирует технические детали от потребителя функции, позволяя программисту не думать об этих деталях. Таким образом, несмотря на то, чтоfind
он, вероятно, реализован с помощью цикла for, он все же помогает сделать код более читабельным, и поскольку он часто находится в стандартной библиотеке, его использование не приводит к значительным накладным расходам или риску.Все сводится к тому, что именно означает «лучше». Для практических программистов это обычно означает эффективность - т. Е. В этом случае выход непосредственно из цикла исключает одно дополнительное сравнение, а возврат логической константы позволяет избежать повторного сравнения; это экономит циклы. Дейкстра больше заботится о создании кода, который легче доказать, что он правильный . [мне показалось, что CS-образование в Европе относится к «проверке правильности кода» гораздо серьезнее, чем CS-образование в США, где экономические силы имеют тенденцию доминировать в практике кодирования]
источник