После строки


У меня это как вопрос интервью, и интервьюер указал на это. Вот что я писал:

//C# Syntax here
public string Reverse(string s)
{
    char[] arr = s.ToCharArray();
    int idx = 0;
    int endIdx = s.Length - 1;
    for(; idx < endIdx; ++idx, --endIdx)
    {
        char temp = arr[idx];
        arr[idx] = arr[endIdx];
        arr[endIdx] = temp;
    }
    return arr.ToString();
}

Однако, интервьюер спрашивает, Если я должен изменить его к этому:

//C# Syntax here
public string Reverse(string s)
{
    char[] arr = s.ToCharArray();
    int idx = 0;
    int endIdx = s.Length - 1;
    while(idx < endIdx)
    {
        char temp = arr[idx];
        arr[idx] = arr[endIdx];
        arr[endIdx] = temp;
        ++idx;
        --endIdx;
    }
    return arr.ToString();
}

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

Однако некоторые программисты ненавидят положить, что вещи в ДЛЯ, потому что они думают, что это слишком "умно".

Что вы считаете наилучшей практики для этого?



Комментарии
11 ответов

Я хотел возразить против его изменения. Это похоже на то, что для петли были изобретены для. Кроме того, почему бы не поставить инициализации в цикле for?

Я бы тоже предпочел

for(int idx=0; idx < endIdx; ++idx, --endIdx) {

если только потому, что мне не придется сканировать вверх и вниз по странице ищу инициализации индекса IDx.

14
ответ дан 31 марта 2011 в 04:03 Источник Поделиться

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

для (int я = значений startvalue; я < endvalue с; я++) {...}

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

в IDx++, --endIdx

Я не ожидал такого рода вещи в течение цикла. Я бы больше знал что-то подобное может произойти, в то время как петли.

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

12
ответ дан 31 марта 2011 в 08:03 Источник Поделиться

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


  1. Нет необходимости, чтобы преобразовать строку в массив char. Не звоня ToCharArray() вы избавляетесь от лишнего копирования данных.

  2. Плохо именованные переменные ИМХО. (Конвенция для индекса-это я.)

  3. Не нужно вычитать с конца показатель. (который я предпочитаю называть длину как конвенции)

  4. Вы не должны вызвать метод toString(), но использовать конструктор строки. Ваш код выводит параметр typename вместо обратной строкой.

В целом:

public string Reverse( string s )
{
int length = s.Length;
char[] reversed = new char[ length ];

for ( int i = 0; i < length; ++i )
{
reversed[ i ] = s[ length - 1 - i ];
}

return new string( reversed );
}

И конечно, правильным решением будет использовать обратный() от интерфейса IEnumerable. Но это не часть вопроса, возможно.

return new string( s.Reverse().ToArray() );


Интересная статья, которая сравнивает различные реверс строки реализации можно найти здесь.

Жаль, что ты упомянула здесь от программистов.ЮВ, ИМХО вы касаетесь некоторые моменты, которые прекрасно обсуждаемые на программистов.

11
ответ дан 7 апреля 2011 в 10:04 Источник Поделиться

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

Я хотел бы выразить вашу функцию такой:

public string Reverse(string s)
{
char[] arr = s.ToCharArray();
for (int i = 0, j = s.Length - 1; i < j; ++i, --j)
{
char swap = arr[i];
arr[i] = arr[j];
arr[j] = swap;
}
return arr.ToString();
}

Из всего цикла заголовка, достаточно опытный программист может распознавать идиомы, что наступаю два массива индексов, пока они не встретятся посередине. По соглашению, я и Джей массива индексов; вам не нужно ...IDx в Венгрии суффикс.

Для сравнения, предложение интервьюера выглядит неструктурированные. Я чувствую, что я мысленно декомпилировать его обратно в цикл for, чтобы понять, что происходит.

Я также переименовал темп , чтобы поменять как молчаливый "комментарий".


Вы можете быть удивлены, до какой крайности можно уложить логики в цикле for заголовка? На практике, я никогда не видел более удачной для-петли заголовок, который участвует более, чем двумя переменными. Вероятное объяснение заключается в том, что условие обычно включает в себя двоичный оператор сравнения. Поэтому третьей переменной, как правило, быть "вне темы" для заголовка.

Две другие рекомендации вы могли бы хотеть использовать это:


  • Если вы можете заполнить все три части заголовка (инициализатор; условие; обновление), то цикл for-Это, наверное, правильно.

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

3
ответ дан 9 декабря 2013 в 09:12 Источник Поделиться

@Билли Онил : я твердо верю, что это дело вкуса. Роберт С. Мартин государств в Чистый код , что разработчики программного обеспечения, как для использования обфускации кода для "покрасоваться" и я с ним согласен. Мне тоже понравился, только я начал работать на мой первый сложный проект и я понял, что дополнительные сопоставления ума не надо.

Что было сказано, мой вариант будет использовать при() цикл; я думаю, что мы можем пойти здесь тот же принцип, который применяется к методу: цикл должен сделать одну вещь и одну вещь только (личное мнение экстраполировать от Чистый код). Так что, если я смотрю на кусок кода после 4 часов бесконечной отладки, он может чувствовать себя более удобным для чтения (я только отформатировал код для удобства чтения):

     //top-down reading per loop
while (UnswitchedCharactersExist())
{
SwitchCharacters(arr, idx, endIdx);
IncrementStartIndex();
DecrementEndIndex();
}

чем:

     //read the initializer, the condition, the code block and go back up for the update
//after that read the condition, the code block and go back up for the update
for(; UnswitchedCharactersExist(); IncrementStartIndex(), DecrementEndIndex())
{
SwitchCharacters(arr, idx, endIdx);
}

Мои 2 цента по этому вопросу.

1
ответ дан 19 декабря 2013 в 11:12 Источник Поделиться

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

Я бы ожидал увидеть что-то гораздо больше, как это:

public static string Reverse(this string s)
{
return s.Aggregate("", (acc, el) => el + acc);
}

Т. е. реализован в левый раз.

Ведь, обращая любой последовательности (не только строки), действительно так же, как

foldl (flip (:)) []

0
ответ дан 1 апреля 2011 в 01:04 Источник Поделиться

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


  • У индекса к фронту и обратно в цикл

  • Есть указатель на фронт и обратно в цикл while

  • Есть один показатель, и вычислять смещение от конца петлю каждый раз вокруг петли

  • Все вышеперечисленные возможности, но инкрементировать/декрементировать указатель на char, а не указатель на массив (по крайней мере в C, вы можете сделать это в C# ?)

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

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

0
ответ дан 1 апреля 2011 в 11:04 Источник Поделиться

Я собирался написать это как комментарий, но вышел из пространства, так...

В общих чертах, я согласен с Петром Leppert; думаю, в то время как здесь более идиоматические.

Конечно C по синтаксис позволяет использовать в первом случае, и в простых функций я не думаю, что это действительно имеет значение, но затем, позволяет ли реализовать все функции в заголовке цикла for с пустым телом, и это не делает его хорошей идеей ;-).

Ваш заголовок был

for(; idx < endIdx; ++idx, --endIdx)

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

for(int idx = 0, endIdx = s.Length - 1; idx < endIdx; ++idx, --endIdx)

Хорошо, достаточно ярмарка. Теперь вам нужна еще одна контрольная переменная для новой функции:

for(int idx = 0, endIdx = s.Length - 1, otherVar = FunctionCall(param1, param2); idx < endIdx && otherVar < AnotherFunctionCall(param1); ++idx, --endIdx, otherVar += 5)

Что же теперь, а? Он получает уродливые очень быстро. Это не масштабирование, а где вы поместите линию? Ограничение на количество символов в заголовке? Только две переменные управления?

Вот почему я хочу делать обычный цикл for:

for (int i = 0; i < maxI; i++)
{
...
}

и использовать время на все остальное.

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

0
ответ дан 3 апреля 2011 в 12:04 Источник Поделиться

Хотя как и в то время как петли и обе будут работать, но, как правило, для петли лучше подходит в этом случае, потому что


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

  • Переменная индекс (IDx в данном случае), это более уместно в области, почему мы должны увеличивать объем индекса IDx, когда это предназначается только для использования внутри цикла.

  • В отличие от цикла while, операторы продолжения и т. д. (если требуется) могут быть использованы без каких-либо проблем.

В то время как цикл должен быть обычно используется, если мы не знаем количество итераций заранее.

0
ответ дан 9 декабря 2013 в 10:12 Источник Поделиться

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

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

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

Кстати, еще один очень хороший ответ, чтобы сказать: "в моем коде я использую обратный() на массив, потому что это уже проверено". Работодатель вообще не хочет платить вам, чтобы изобретать колесо, а в качестве интервьюера я бы оценил глубину вашего опыта, что показывает.

0
ответ дан 10 декабря 2013 в 02:12 Источник Поделиться

Все вещи в сторону, я считаю, что эти два куска кода работать по-разному. Первый predecrement, второй пост.

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

Я думаю, что цикл for-это вполне правомерный подход к то подобное. Если вы находите, что делает цикл for и оператор if размещения почти в самом начале, тогда вы можете хотеть рассмотреть, используя цикл while.

-2
ответ дан 10 декабря 2013 в 12:12 Источник Поделиться