Ясный способ пропустить первый элемент в индексе на основе цикла

9

У меня есть цикл for, где я должен пропустить первый элемент массива с нуля.

Что из этого показывает мои намерения более четко?

for($i=1 ; $i < count(array) ; $i++){
    array[$i];
}

или

for($i=0+1 ; $i < count(array) ; $i++){
    array[$i];
}
Томас Зубири
источник
28
Ни один из них не $i=2-1является лучшим способом. : /
Яннис
7
Я бы, вероятно, выбрал первый вариант и добавил комментарий, чтобы объяснить, почему первый элемент должен быть пропущен.
Винсент Савард
3
Я стремлюсь к ясности, я отредактировал вопрос. Это понятнее?
Томас Зубири
10
Не использовать PHP - лучший способ.
кот
3
Есть ли в PHP конструкция foreach? Вы можете сделать foreach ($i in range(1, count))(как это выглядит в PHP). Или что-то вроде foreach ($item in array.skip(1))того, что сделал бы человек C #.
USR

Ответы:

23

Я ненавижу оба.

Кто сказал, что вы можете использовать магические числа? Если вы собираетесь начать со смещения 1, как насчет того, чтобы сказать нам, ПОЧЕМУ вы начинаете со смещения 1. Добавление одинаково магического нуля мне ничего не объясняет.

Это смещение полезной нагрузки? Это какая-то строка паскаля, которую вы конвертируете в строку c с нулевым символом в конце? Пожалуйста, расскажите нам, что происходит.

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

Под приличным именем я подразумеваю имя, которое объясняет, ПОЧЕМУ мы пропускаем первый элемент. Не то, что просто говорит, что мы пропускаем первый элемент. 1 сказал мне, что сам по себе.

candied_orange
источник
20
0 и 1 не являются магическими числами.
user949300
19
@ user949300 О, они, конечно, здесь. Это просто числа, которые иногда не являются волшебными. Тот факт, что 2 всегда является магическим числом, не означает, что 1 никогда не является магическим числом. Магия исходит из недостающего значения. Что, черт возьми, означает здесь, начиная с 1 смещения? Что хорошего в добавлении 0 здесь? О, да, эти цифры, безусловно, волшебны. Я вижу, как с них капает пыльца пикси.
candied_orange
4
Конечно, я начну определять static final int LONELIEST_NUMBER = 1во всем своем коде Java. :-) Тем не менее, если подумать, я бы хотел отменить ваш ответ, но не смогу, если вы его не отредактируете. Глупое ТАКОЕ правило?
user949300
6
@Eiko: Если нет объяснения, почему цикл начинается со второго элемента, фактически гарантируется, что некоторый программист по обслуживанию изменит цикл, чтобы начать с первого элемента. Вот почему цифра 1 является магическим числом в этом контексте.
Барт ван Инген Шенау
2
@BartvanIngenSchenau Я предполагал, что внутри контекста будет очевидная причина. Например, сравнивать элементы с их предшественниками (что я считаю наиболее распространенным вариантом использования, начиная с 1 - и я не вижу здесь никакого полезного имени константы). Если первый элемент имеет какое-то сверхспециальное значение, дизайн может быть неработоспособным, и исправления должны быть лучше, чем называть этот индекс. Я не говорю, что нет никакой причины вводить переменную здесь. Просто я думаю, что такие случаи (или, возможно, должны быть) очень редки.
Эйко
12

Краткий ответ: первый вариант лучше.

Второй вариант просто добавляет шум. Маловероятно, что 0 + 1 помогает читателю понять, что это могло быть 0, но оно равно 1. Гораздо более вероятно, что он будет озадачен коротким моментом и отвлечен от того, о чем идет речь. Особенно на языке, где все массивы начинаются с 0.

Как уже упоминалось, если вы хотите подчеркнуть тот факт, что цикл начинается с 1, а не с 0, просто добавьте комментарий.

Флориан Ф
источник
10

Не говорите нам, что вы пропустили первый пункт - мы это видим. Что не очевидно, так это почему . Итак ... если это не очевидно из контекста, скажите нам, почему:

// array[0] is just a header
for($i=1 ; $i < count(array) ; $i++){
    array[$i];
}

Или, если вы не любите комментировать, что-то вроде:

$lastHeaderIndex = 0;
for($i = $lastHeaderIndex + 1 ; $i < count(array) ; $i++){
    array[$i];
}

Не используйте комментарии и хитрости, чтобы напомнить нам, как работает язык.

svidgen
источник
6

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

for($i=1 ; $i < count(array) ; $i++){
    array[$i-1]=array[$i];
}

не было бы никакого объяснения или конструкции «0 + 1», необходимой, чтобы прояснить, почему цикл начинается с 1 вместо 0.

Однако, если код внутри цикла не объясняет причины столь очевидным образом (возможно, array[0]имеет особое значение и должен рассматриваться не так, как остальные элементы), добавьте поясняющий комментарий. Но прежде чем сделать это, подумайте дважды, сможете ли вы избежать array[0]такого особого значения, и реорганизуйте окружающий код, который, вероятно, будет лучшей альтернативой.

Док Браун
источник
В ситуациях, подобных вашему примеру кода, мне нравится называть переменные «oneBasedIndex» или «zeroBasedIndex». Хотя что-то еще более конкретное для этой задачи будет лучше.
user949300
5

Никогда не видел вариант № 2, но мне это нравится. Почему? При выборе опции 1 я хотел бы знать, забыл ли программист, что массивы начинаются с 0. Опция 2 проясняет, что они намеренно начинаются с 1.

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

Или, если вы можете легко описать, почему вы начинаете с одного, используйте константу. Например, если посмотреть на аргументы командной строки, что-то вроде

define ('FIRST_REAL_ARGUMENT', 1);
for ($i=FIRST_REAL_ARGUMENT; ...)

Лично я бы, наверное, просто использовал комментарий, YMMV.

user949300
источник
Я скажу, что вне среды, где вы имеете дело с новичками, у меня никогда не было проблемы с коллегами, забывшими, что массивы начинаются с нуля. Я мог видеть это, если бы ваша работа также использовала такой язык, как MATLAB, но в большинстве сред я бы предположил, что программист знал, что они делают. И, черт возьми, начало цикла в 1 довольно чертовски часто. Есть немало причин, чтобы пропустить первый элемент чего-либо.
Kat
@Kat Эту причину нужно понять будущим читателям. Я предпочел бы предположить, что будущий программист не знает, что он делает.
A1rPun
2

Я сомневаюсь, что кто-то будет смущен первым. Мы все должны были сделать это. Настолько, что второй с большей вероятностью запутает. «Почему там 0+? Они как-то переопределяют оператор +?»

Приличный компилятор все равно превратит второй в первый, но похоже, что вы используете PHP, что интерпретируется. Таким образом, каждый раз, когда интерпретатор попадает в этот цикл, ему фактически необходимо добавить 0 и 1. Ничего страшного, но зачем переводчику делать работу?

Кевин Фе
источник
2

Используйте переменную, которая объясняет начальную точку.

Вам необходимо « пропустить первый элемент массива с нуля », например:

skipFirstElement = 1;

for($i=$skipFirstElement ; $i < count(array) ; $i++){
    array[$i];
}
Катта
источник
6
Мне нравится использовать переменную, но я ненавижу это имя. Это не объясняет, ПОЧЕМУ вы пропускаете первый элемент. В любом случае, 1 говорит мне об этом. Что хорошего в переменной, которую нужно переименовывать при изменении значения? Я знаю, что ОП не дал нам ни малейшего понятия, почему так, чтобы выбрать хорошее имя, вы должны будете обосновать причину. Без лучшего имени я бы предпочел 1 назад.
candied_orange
@CandiedOrange Я согласен с вами, что имя переменной должно быть более значимым, но проблема в том виде, в котором она представлена, не объясняет, почему он хочет пропустить первое значение. Моя точка зрения, я просто приведу пример, автор может выбрать имя, которое лучше всего подходит для него.
Catta
Пожалуйста, не учите так. Это достаточно запутанно. Многие кодировщики найдут самое простое имя, какое только смогут, чтобы вернуться к написанию сложного для понимания кода. Серьезно, я бы предпочел иметь дело с 1, чем с этим.
candied_orange
1
//We are skipping the first element because...    
if ($i==0)  
{    continue;      } 

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

Джон Рейнор
источник
2
Проблема с этой опцией означает, что мы собираемся оценивать это для каждого отдельного элемента, добавляя n дополнительных сравнений в цикл, просто пропуская первое с помощью другого метода (сдвиг массива, начиная с i = 1, что угодно ) означает делать только ту работу, которая вам нужна.
Кевин Фее,
3
@KevinFee Если вы не имеете дело с массивными массивами, я бы сказал, что это простое сравнение не будет проблемой. И мне очень нравится откровенность if first then skipс комментарием, объясняющим почему. Все же без контекста ни одно из решений не является «лучшим»
Иван Пинтар
-2

Что бы я сделал, это удалил первый элемент перед циклом. Создайте новый массив, если вам нужно. Объясните в комментарии, почему вы это делаете. А потом просто сделай простой foreach.

$arrayCopy = $array; // in case you don't want to touch the original array
array_shift($arrayCopy); // removing first element because of X reason.
foreach($arrayCopy => $element) { 
    // do stuff
}

Таким образом, ваше намерение совершенно ясно.

Чтобы уточнить, вы можете обернуть код в метод с соответствующим именем, чтобы прояснить ситуацию.

function doStuffToAllButTheFirst($array) { // this copies the original array, so there are no sideffects
    array_shift($array);
    foreach($array => $element) { // do stuff }  
}

Однако все это все еще отсутствует контекст. Что вы хотите сделать с элементами? Будете ли вы возвращать новый массив? Вы заботитесь об оригинале и новом массиве после вас doStuff()?

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

Иван Пинтар
источник
1
Мне это нравится, потому что мне сейчас не нужно разбираться с индексами, что всегда является плюсом.
Томас Зубири
1
Недостатком здесь является то, что если вы не хотите побочных эффектов, вам нужно скопировать весь массив.
Томас Зубири
1
А что, если причина, с которой мы начинаем с 1, заключается в том, что мы делаем $array[$i-1] = $array[$i]или что-то подобное, согласно ответу @ DocBrown?
Кевин Фее
1
Это кажется мне ужасным. Помимо неэффективности, побочных эффектов и неспособности решить довольно распространенные случаи использования 1(см. Комментарий Кевина Ли), это вовсе не делает код более понятным. Читатель должен понимать array_shift, что он делает, как он работает. Может быть, эта строка кода является ошибкой? Модифицирует ли массив или возвращает новый? Вставляет ли элемент или удаляет один? Меняет ли это индексы или нет? Я не вижу, как использование цикла на основе одного не будет огромным улучшением в этой функции (и, учитывая его имя, сразу понятно).
Эйко
1
Ответы на эти вопросы сильно зависят от контекста. А что касается эффективности, я бы взял на себя предвидение на любой день ... Любая разница в производительности почти невидима в большинстве случаев.
Иван Пинтар