Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve loops #106

Merged
merged 4 commits into from
Dec 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
49 changes: 49 additions & 0 deletions modules/50-loops/26-conditions-inside-loops/description.ru.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---

name: Условия внутри тела цикла
theory: |

Тело цикла, как и тело функции — это место выполнения инструкций. Значит, мы можем использовать внутри него всё изученное ранее, например — условные конструкции.

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

```python
count_chars('Fear cuts deeper than swords.', 'e') # 4
# Если вы ничего не нашли, то результат — 0 совпадений
count_chars('Sansa', 'y') # 0
```

Перед тем как посмотреть её содержимое, попробуйте ответить на вопросы:

* Является ли эта операция агрегацией?
* Какой будет проверка на вхождение символа?

```python
def count_chars(string, char):
index = 0
count = 0
while index < len(string):
if string[index] == char:
# Считаем только подходящие символы
count = count + 1
# Счётчик увеличивается в любом случае
index = index + 1
return count
```

Эта задача является агрегирующей. Несмотря на то, что она считает не все символы, для подсчёта самой суммы все равно приходится анализировать каждый символ.

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

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

instructions: |

Функция из теории учитывает регистр букв. То есть `A` и `a` с её точки зрения разные символы. Реализуйте вариант этой же функции, так чтобы регистр букв был не важен:

```python
count_chars('HexlEt', 'e') # 2
count_chars('HexlEt', 'E') # 2
```

tips: []
13 changes: 13 additions & 0 deletions modules/50-loops/26-conditions-inside-loops/index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from hexlet.code_basics import to_upper_case


# BEGIN
def count_chars(string, char):
index = 0
count = 0
while index < len(string):
if to_upper_case(string[index]) == to_upper_case(char):
count = count + 1
index = index + 1
return count
# END
8 changes: 8 additions & 0 deletions modules/50-loops/26-conditions-inside-loops/test_code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import index


def test1():
assert index.count_chars('axe', 'a') == 1
assert index.count_chars('', 'a') == 0
assert index.count_chars('opPa', 'p') == 2
assert index.count_chars('opPa', 'P') == 2
2 changes: 2 additions & 0 deletions modules/50-loops/28-build-string/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test:
@ test.sh
61 changes: 61 additions & 0 deletions modules/50-loops/28-build-string/description.ru.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---

name: Формирование строк в циклах
theory: |

Ещё одно использование циклов – формирование строк. Подобная задача нередко встречается в веб-программировании. Она сводится к обычной агрегации с применением интерполяции или конкатенации.

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

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

```python
def reverse_string(string):
index = len(string) - 1
reversed_string = ''

while index >= 0:
current_char = string[index]
reversed_string = reversed_string + current_char
# То же самое через интерполяцию
# reversed_string = "{}{}".format(reversed_string, current_char)
index = index - 1

return reversed_string

reverse_string('Game Of Thrones') # 'senorhT fO emaG'
# Проверка нейтрального элемента
reverse_string('') # ''
```

Разберём функцию построчно:

* `index = len(string) - 1` — записываем в новую переменную индекс последнего символа строки (напомним, что индексы начинаются с нуля).
* `reversed_string = ''` — инициализируем строку, куда будем записывать результат.
* `while index >= 0:` — условие: повторяем тело цикла, пока текущий индекс не дошёл до `0`, то есть до первого символа.
* `current_char = string[index]` — берём из строки символ по текущему индексу.
* `reversed_string = reversed_string + current_char` — записываем в строку-результат новое значение: текущая строка-результат + новый символ.
* `index = index - 1` — обновляем счётчик
* `return reversed_string` — когда цикл завершился, возвращаем строку-результат.

Обязательно скопируйте эту функцию в [https://repl.it/languages/python3](https://repl.it/languages/python3) и поэкспериментируйте с ней.

Работая со строками, программисты часто допускают ошибку «выход за границы строки». При неправильном подборе начального значения счётчика или ошибке в предикате цикла может получиться ситуация, при которой идёт обращение к несуществующему символу.

Особенно часто забывают о том, что индекс последнего элемента всегда меньше на единицу размера строки. В строках начальный индекс равен `0`, а значит индекс последнего элемента — `len(str) - 1` (длина минус 1).

instructions: |

Реализуйте функцию `my_substr()`, которая извлекает из строки подстроку указанной длины. Она принимает на вход два аргумента: строку и длину, и возвращает подстроку, начиная с первого символа:

Пример вызова:

```python
string = 'If I look back I am lost'
print(my_substr(string, 1)) # => 'I'
print(my_substr(string, 7)) # => 'If I lo'
```

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

tips: []
9 changes: 9 additions & 0 deletions modules/50-loops/28-build-string/index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# BEGIN
def my_substr(string, length):
result_string = ''
index = 0
while index < length:
result_string = result_string + string[index]
index = index + 1

return result_string
7 changes: 7 additions & 0 deletions modules/50-loops/28-build-string/test_code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import index


def test1():
assert index.my_substr('got', 3) == 'got'
assert index.my_substr('got', 2) == 'go'
assert index.my_substr('got', 1) == 'g'
2 changes: 2 additions & 0 deletions modules/50-loops/29-edge-cases/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test:
@ test.sh
13 changes: 4 additions & 9 deletions modules/50-loops/30-syntactic-sugar/description.ru.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,14 @@ theory: |

instructions: |

Реализуйте функцию `count_chars()`, которая считает повторения указанного символа в строке (в программировании говорят «количество вхождений символа в строке»).

Функция принимает на вход два параметра: строку и символ. Функция возвращает число.
Реализуйте функцию `filter_string()`, принимающую на вход строку и символ, и возвращающую новую строку, в которой удален переданный символ во всех его позициях.

Пример вызова:

```python
string = 'If I look back I am lost'
print(count_chars(string, 'I')) # => 3
print(count_chars(string, 'z')) # => 0
print(count_chars(string, 'o')) # => 3
text = 'If I look back I am lost'
filter_string(text, 'I') # 'f look back am lost'
filter_string(text, 'o') # 'If I lk back I am lst'
```

Идея в том, чтобы создать отдельную переменную-счётчик и увеличивать её на 1 каждый раз, когда в строке встречается указанный символ. Вам понадобится вложить условный оператор в тело цикла. Для увеличения счётчика используйте синтаксический сахар.

tips: []
15 changes: 8 additions & 7 deletions modules/50-loops/30-syntactic-sugar/index.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
def count_chars(string, char):
index = len(string) - 1
result = 0
while index >= 0:
if string[index] == char:
result += 1
index -= 1
def filter_string(text, char):
index = 0
result = ''
while index < len(text):
current_char = text[index]
if current_char != char:
result += current_char
index += 1
return result
9 changes: 4 additions & 5 deletions modules/50-loops/30-syntactic-sugar/test_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@


def test1():
string = 'If I look back I am lost'
assert index.count_chars(string, 'I') == 3
assert index.count_chars(string, 'z') == 0
assert index.count_chars(string, 'o') == 3
assert index.count_chars(string, 't') == 1
text = 'If I look back I am lost'
assert index.filter_string(text, 'w') == 'If I look back I am lost'
assert index.filter_string(text, 'I') == 'f look back am lost'
assert index.filter_string('zz zorro', 'z') == ' orro'