Skip to content

Commit

Permalink
improve loops (#106)
Browse files Browse the repository at this point in the history
* improve loops

* improve 30-syntactic-sugar example

* fix lint

* fix test
  • Loading branch information
zhabinka committed Dec 8, 2020
1 parent 0244327 commit 419f11f
Show file tree
Hide file tree
Showing 15 changed files with 167 additions and 21 deletions.
File renamed without changes.
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
File renamed without changes.
File renamed without changes.
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'

0 comments on commit 419f11f

Please sign in to comment.