Каппес Даниил Олегович

ПРАКТИКУМ PYTHON · ЗАНЯТИЕ 8

Списки: добавление и удаление, вывод, split и join

Список наполняется на ходу, печатается как нужно — и наконец получает мост к строкам: split() и join().

Чему научимся

Добавление: append и extend

Метод append() добавляет один элемент в конец списка:

numbers = [1, 1, 2, 3, 5, 8, 13]
numbers.append(21)
numbers.append(34)
print(numbers)

Результат

[1, 1, 2, 3, 5, 8, 13, 21, 34]

Список при этом должен уже существовать — пусть даже пустой. Это обычный приём: создать пустой список и наполнить его в цикле.

Обращаться по индексу к тому, чего ещё нет, нельзя. numbers = [] и следом numbers[0] = 1 остановит программу: IndexError: list assignment index out of range. Индекс годится, чтобы заменить существующий элемент, а не создать новый.

Метод extend() добавляет не один элемент, а сразу все элементы другого списка:

numbers = [0, 2, 4, 6, 8, 10]
odds = [1, 3, 5, 7]
numbers.extend(odds)
print(numbers)

Результат

[0, 2, 4, 6, 8, 10, 1, 3, 5, 7]

Разница между ними виднее всего на строке:

words1 = ['stepik', 'beegeek']
words2 = ['stepik', 'beegeek']
words1.append('python')
words2.extend('python')
print(words1)
print(words2)

Результат

['stepik', 'beegeek', 'python']
['stepik', 'beegeek', 'p', 'y', 't', 'h', 'o', 'n']

append() положил строку целиком, а extend() разобрал её на символы: он добавляет элементы того, что ему дали, а элементы строки — это её символы.

Удаление: оператор del

Оператор del удаляет элемент по индексу. Пишется он без скобок — это не метод, а именно оператор:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
del numbers[5]
print(numbers)

Результат

[1, 2, 3, 4, 5, 7, 8, 9]

После удаления список перестраивается: элементы сдвигаются, и индексы у них меняются. Это важно, когда удаляют несколько раз подряд.

del работает и со срезом — тогда удаляется целый кусок:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
del numbers[2:7]
print(numbers)

Результат

[1, 2, 8, 9]
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
del numbers[::2]
print(numbers)

Результат

[2, 4, 6, 8]

Срез с шагом здесь особенно удобен: del numbers[::2] убирает элементы с чётными индексами — то, что циклом писалось бы с оглядкой на сдвиг индексов.

8.1

Два del подряд

Исполните следующую программу. Совпадает ли результат с тем, чего вы ожидали? Внесите минимальные исправления, чтобы результатом её выполнения стала печать списка ['red', 'orange', 'green', 'blue', 'purple', 'magenta'].

Код

colors = ['red', 'orange', 'yellow', 'green', 'blue', 'purple', 'brown', 'magenta']
del colors[2]
del colors[6]
print(colors)
Формат выходных данных
Список из шести цветов.
Вывод
['red', 'orange', 'green', 'blue', 'purple', 'magenta']
Подсказка 1

Убрать нужно yellow и brown. Первое удаление верное — посмотрите, что стало со списком после него.

Подсказка 2

После первого del все элементы правее сдвинулись на одну позицию влево, и brown оказался не под шестым индексом, а под пятым.

Разбор
  1. del colors[2] убирает yellow — это верно.
  2. В получившемся списке brown стоит под индексом 5, а не 6.
  3. del colors[6] в исходном коде удаляет magenta — не тот цвет.
Решение
colors = ['red', 'orange', 'yellow', 'green', 'blue', 'purple', 'brown', 'magenta']

del colors[2]   # убрали yellow — остальные сдвинулись влево
del colors[5]   # было colors[6]: brown теперь под пятым индексом

print(colors)

Это главная ловушка удаления по индексу: индексы «плывут» после каждого del. Когда удалений несколько, надёжнее идти с конца — тогда сдвиг не затрагивает ещё не удалённые элементы.

8.2

Пять вопросов к списку

Дополните приведённый код так, чтобы он по очереди вывел:

  1. длину списка;
  2. последний элемент списка;
  3. список в обратном порядке;
  4. YES, если список содержит числа 5 и 17, и NO в противном случае;
  5. список с удалёнными первым и последним элементами.

Код

numbers = [2, 6, 3, 14, 10, 4, 11, 16, 12, 5, 4, 16, 1, 0, 8, 16, 10, 10, 8, 5,
           1, 11, 10, 10, 12, 0, 0, 6, 14, 8, 2, 12, 14, 5, 6, 12, 1, 2, 10, 14,
           9, 1, 15, 1, 2, 14, 16, 6, 7, 5]
print(len(numbers))
Формат выходных данных
Пять строк.
Вывод
50
5
[5, 7, 6, 16, 14, 2, 1, 15, 1, 9, 14, 10, 2, 1, 12, 6, 5, 14, 12, 2, 8, 14, 6, 0, 0, 12, 10, 10, 11, 1, 5, 8, 10, 10, 16, 8, 0, 1, 16, 4, 5, 12, 16, 11, 4, 10, 14, 3, 6, 2]
NO
[6, 3, 14, 10, 4, 11, 16, 12, 5, 4, 16, 1, 0, 8, 16, 10, 10, 8, 5, 1, 11, 10, 10, 12, 0, 0, 6, 14, 8, 2, 12, 14, 5, 6, 12, 1, 2, 10, 14, 9, 1, 15, 1, 2, 14, 16, 6, 7]
Подсказка 1

Четыре из пяти пунктов — это уже знакомые индексы и срезы.

Подсказка 2

«Содержит 5 и 17» — два условия через and, каждое проверяется оператором in.

Разбор
  1. Последний элемент — numbers[-1].
  2. Обратный порядок — срез numbers[::-1].
  3. Проверка: 5 in numbers and 17 in numbers; числа 17 в списке нет, поэтому ответ NO.
  4. Без первого и последнего — срез numbers[1:-1].
Решение
numbers = [2, 6, 3, 14, 10, 4, 11, 16, 12, 5, 4, 16, 1, 0, 8, 16, 10, 10, 8, 5,
           1, 11, 10, 10, 12, 0, 0, 6, 14, 8, 2, 12, 14, 5, 6, 12, 1, 2, 10, 14,
           9, 1, 15, 1, 2, 14, 16, 6, 7, 5]

print(len(numbers))
print(numbers[-1])
print(numbers[::-1])

if 5 in numbers and 17 in numbers:
    print('YES')
else:
    print('NO')

print(numbers[1:-1])   # срез без первого и последнего элементов

Срез [1:-1] — типичный приём «отрезать края». Он не меняет исходный список: numbers остался прежним, а print() показал новый список.

8.3

Список из строк

На вход подаётся натуральное число n, а затем n строк. Напишите программу, которая создаёт из этих строк список и выводит его.

Формат входных данных
Число n, затем n строк.
Формат выходных данных
Список целиком.
Ввод
5
C#
C++
C
Python
F#
Вывод
['C#', 'C++', 'C', 'Python', 'F#']
Подсказка 1

Начинают с пустого списка — наполнять будем в цикле.

Подсказка 2

Каждую прочитанную строку добавляют методом append().

Разбор
  1. Читаем n.
  2. Заводим пустой список.
  3. n раз читаем строку и добавляем её в конец списка.
  4. Печатаем список целиком.
Решение
n = int(input())

words = []                 # пустой список, который сейчас наполним
for i in range(n):
    words.append(input())

print(words)

Пара «пустой список плюс append() в цикле» — самый частый способ собрать данные. Обратите внимание: input() стоит прямо внутри append() — отдельная переменная тут ничего не добавляет.

8.4

a, bb, ccc…

Напишите программу, выводящую список ['a', 'bb', 'ccc', 'dddd', 'eeeee', …], где последний элемент состоит из 26 букв z.

Полезно вспомнить, что в таблице символов код буквы a равен 97.

Формат выходных данных
Список из 26 элементов.
Вывод
['a', 'bb', 'ccc', 'dddd', 'eeeee', 'ffffff', 'ggggggg', 'hhhhhhhh', 'iiiiiiiii', 'jjjjjjjjjj', 'kkkkkkkkkkk', 'llllllllllll', 'mmmmmmmmmmmmm', 'nnnnnnnnnnnnnn', 'ooooooooooooooo', 'pppppppppppppppp', 'qqqqqqqqqqqqqqqqq', 'rrrrrrrrrrrrrrrrrr', 'sssssssssssssssssss', 'tttttttttttttttttttt', 'uuuuuuuuuuuuuuuuuuuuu', 'vvvvvvvvvvvvvvvvvvvvvv', 'wwwwwwwwwwwwwwwwwwwwwww', 'xxxxxxxxxxxxxxxxxxxxxxxx', 'yyyyyyyyyyyyyyyyyyyyyyyyy', 'zzzzzzzzzzzzzzzzzzzzzzzzzz']
Подсказка 1

Буквы идут подряд по кодам: chr(97) — это a, chr(98)b.

Подсказка 2

Сколько раз повторить букву, зависит от её номера: первая — один раз, вторая — два.

Разбор
  1. Заводим пустой список.
  2. Перебираем номера от 0 до 25.
  3. Буква — это chr(97 + i), повторить её надо i + 1 раз.
  4. Добавляем получившуюся строку в список.
Решение
letters = []

for i in range(26):
    letter = chr(97 + i)          # 97 — код буквы 'a'
    letters.append(letter * (i + 1))

print(letters)

Здесь сошлись сразу три приёма: коды символов из прошлого занятия, умножение строки на число и наполнение списка. Каждый по отдельности прост — сложность только в том, чтобы увидеть, как они складываются.

8.5

Список кубов

На вход подаётся натуральное число n, а затем n целых чисел. Напишите программу, которая создаёт из этих чисел список их кубов и выводит его.

Формат входных данных
Число n, затем n целых чисел.
Формат выходных данных
Список кубов.
Ввод
4
1
2
3
4
Вывод
[1, 8, 27, 64]
Подсказка 1

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

Подсказка 2

Куб — это x ** 3.

Разбор
  1. Читаем n и заводим пустой список.
  2. n раз читаем число, возводим в куб и добавляем результат.
  3. Печатаем список.
Решение
n = int(input())

cubes = []
for i in range(n):
    x = int(input())
    cubes.append(x ** 3)

print(cubes)

Список хранит уже готовые кубы, а не исходные числа. Так и стоит поступать, когда исходные значения дальше не понадобятся: лишние данные — лишний повод запутаться.

8.6

Суммы соседей

На вход подаётся натуральное число n ≥ 2, а затем n целых чисел. Напишите программу, которая создаёт из них список сумм соседних чисел: 0-го и 1-го, 1-го и 2-го, 2-го и 3-го и так далее.

Формат входных данных
Число n, затем n целых чисел.
Формат выходных данных
Список из n − 1 суммы.
Ввод
5
1
2
3
4
5
Вывод
[3, 5, 7, 9]
Подсказка 1

Пока все числа не прочитаны, соседей сравнивать не с чем: сначала собираем список, потом считаем.

Подсказка 2

Пар соседей на одну меньше, чем чисел.

Разбор
  1. Читаем все n чисел в список.
  2. Перебираем индексы от 0 до n − 2.
  3. Складываем numbers[i] и numbers[i + 1], добавляем сумму во второй список.
Решение
n = int(input())

numbers = []
for i in range(n):
    numbers.append(int(input()))

sums = []
for i in range(n - 1):        # пар соседей на одну меньше, чем чисел
    sums.append(numbers[i] + numbers[i + 1])

print(sums)

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

8.7

Удалить нечётные индексы

На вход подаётся натуральное число n, а затем n целых чисел. Напишите программу, которая создаёт из них список, удаляет все элементы, стоящие по нечётным индексам, и выводит результат.

Используйте оператор del.

Формат входных данных
Число n, затем n целых чисел.
Формат выходных данных
Список без элементов с нечётными индексами.
Ввод
10
0
1
2
3
4
5
6
7
8
9
Вывод
[0, 2, 4, 6, 8]
Подсказка 1

Удалять по одному в цикле опасно: после каждого удаления индексы сдвигаются.

Подсказка 2

del умеет работать со срезом, а у среза есть шаг.

Разбор
  1. Читаем числа в список.
  2. Нечётные индексы — это срез [1::2]: начиная с первого, через один.
  3. Удаляем весь срез одной командой.
Решение
n = int(input())

numbers = []
for i in range(n):
    numbers.append(int(input()))

del numbers[1::2]   # срез «с первого через один» — все нечётные индексы

print(numbers)

Попробуйте сделать это циклом — и наткнётесь ровно на ловушку из задачи 8.1: после первого же удаления половина индексов уедет. Срез удаляет всё разом, до всякого сдвига.

Как выводить список

print(numbers) печатает список со скобками и запятыми — это удобно для отладки, но редко годится как ответ. Способов вывести по-своему два.

Цикл. Если нужны индексы — идём по ним, если нет — по элементам:

for num in numbers:
    print(num)

for num in numbers:
    print(num, end=' ')

Распаковка. Звёздочка перед именем списка передаёт print() не список, а его элементы по отдельности — как если бы вы перечислили их через запятую:

numbers = [0, 1, 2, 3, 4]
print(*numbers)
print(*numbers, sep='\n')

Результат

0 1 2 3 4
0
1
2
3
4

Дальше работают знакомые sep и end: первый пример — через пробел, второй — в столбик. Со строкой распаковка тоже работает: print(*'Python') напечатает буквы через пробел.

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

8.8

Значение функции

На вход подаётся натуральное число n, а затем n целых чисел. Напишите программу, которая для каждого введённого числа x выводит значение функции f(x) = x² + 2x + 1, каждое на отдельной строке.

Формат входных данных
Число n, затем n целых чисел.
Формат выходных данных
n строк со значениями функции.
Ввод
5
1
2
3
4
5
Вывод
4
9
16
25
36
Подсказка 1

Хранить числа не нужно: каждое обрабатывается сразу после чтения.

Подсказка 2

Формула переносится в код буквально: x ** 2 + 2 * x + 1.

Разбор
  1. Читаем n.
  2. n раз читаем очередное число и сразу печатаем значение формулы.
Решение
n = int(input())

for i in range(n):
    x = int(input())
    print(x ** 2 + 2 * x + 1)

Список тут не нужен вовсе — и это стоит замечать. Заводить его «на всякий случай» вредно: чем меньше в программе хранится, тем меньше в ней может разъехаться.

8.9

Убрать выбросы

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

Формат входных данных
Число n, затем n различных натуральных чисел.
Формат выходных данных
Оставшиеся числа, каждое на отдельной строке.
Ввод
10
9
17
189
3
55
78
11
7
888
160
Вывод
9
17
189
55
78
11
7
160
Подсказка 1

Порядок менять нельзя — значит, сортировать список не надо. Нужно просто знать, какие два числа пропустить.

Подсказка 2

min() и max() дадут эти значения, а дальше остаётся вывести всё, кроме них.

Разбор
  1. Читаем все числа в список.
  2. Находим наименьшее и наибольшее.
  3. Перебираем список и печатаем те элементы, которые не равны ни одному из них.
Решение
n = int(input())

numbers = []
for i in range(n):
    numbers.append(int(input()))

smallest = min(numbers)
largest = max(numbers)

for x in numbers:
    if x != smallest and x != largest:
        print(x)

Оговорка «числа различны» здесь не украшение: повторись наименьшее дважды, программа выбросила бы оба. Когда условие что-то гарантирует, это обычно и есть подсказка, каким способом решать.

8.10

Без дубликатов

На вход подаётся натуральное число n, а затем n строк. Напишите программу, которая выводит только уникальные строки, в том же порядке, в котором они были введены.

Формат входных данных
Число n, затем n строк.
Формат выходных данных
Уникальные строки, каждая на отдельной строке.
Ввод
5
first
second
first
third
second
Вывод
first
second
third
Подсказка 1

Чтобы понять, встречалась ли строка раньше, её надо где-то помнить.

Подсказка 2

Оператор in работает и со списком: if s not in seen.

Разбор
  1. Заводим список уже встреченных строк.
  2. Читаем очередную строку.
  3. Если её ещё не было — печатаем и добавляем в список.
  4. Если была — пропускаем.
Решение
n = int(input())

seen = []                  # строки, которые уже встречались
for i in range(n):
    s = input()
    if s not in seen:
        print(s)
        seen.append(s)

Печать стоит внутри условия, а не после цикла, — поэтому порядок вывода совпадает с порядком ввода сам собой. Это и требовалось: «в том же порядке».

split и join: мост между строкой и списком

Два метода, противоположных по смыслу. split() разбивает строку на список слов, join() собирает строку из списка.

s = 'Python is the most powerful language'
words = s.split()
print(words)

Результат

['Python', 'is', 'the', 'most', 'powerful', 'language']

Без параметров split() режет по пробельным символам, а несколько пробелов подряд считает одним разделителем. С параметром — режет ровно по указанной строке:

ip = '192.168.1.24'
print(ip.split('.'))

Результат

['192', '168', '1', '24']

Между s.split() и s.split(' ') разница огромная. Первый разбирает 'a b' в ['a', 'b'], второй — в ['a', '', 'b']: два пробела для него два разделителя, а между ними пустая строка.

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

numbers = input().split()
for i in range(len(numbers)):
    numbers[i] = int(numbers[i])

join() вызывается у строки-разделителя, а в скобках получает список:

words = ['Мы', 'учим', 'язык', 'Python']
print(' '.join(words))
print('*'.join(words))

Результат

Мы учим язык Python
Мы*учим*язык*Python

join() работает только со списком строк. '*'.join([1, 2, 3]) остановит программу: числа сначала надо превратить в строки.

8.11

Слова в столбик

На вход подаётся строка текста. Напишите программу, которая выводит слова введённой строки в столбик.

Формат входных данных
Одна строка со словами.
Формат выходных данных
Слова, каждое на отдельной строке.
Ввод
У лукоморья дуб зеленый златая цепь на дубе том
Вывод
У
лукоморья
дуб
зеленый
златая
цепь
на
дубе
том
Подсказка 1

Строка превращается в список слов одним методом.

Подсказка 2

А вывести список в столбик можно распаковкой с параметром sep.

Разбор
  1. input().split() даёт список слов.
  2. print(*words, sep='\n') печатает их каждое с новой строки.
Решение
words = input().split()

print(*words, sep='\n')

Та же задача циклом заняла бы три строки — и это тоже верное решение. Распаковка выигрывает именно здесь, где все элементы печатаются одинаково.

8.12

Инициалы

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

Формат входных данных
Одна строка: имя, отчество и фамилия через пробел.
Формат выходных данных
Три буквы с точками.
Ввод 1
Владимир Семенович Высоцкий
Вывод 1
В.С.В.
Ввод 2
тимур ахсарбекович гуев
Вывод 2
Т.А.Г.
Подсказка 1

Разбейте строку на части — получится список из трёх слов.

Подсказка 2

Первая буква слова — это его нулевой символ: parts[0][0].

Разбор
  1. input().split() даёт список из трёх слов.
  2. Берём у каждого нулевой символ и переводим в верхний регистр.
  3. Склеиваем их с точками.
Решение
parts = input().split()

# у каждого слова берём первую букву и делаем её заглавной
first = parts[0][0].upper()
second = parts[1][0].upper()
third = parts[2][0].upper()

print(first + '.' + second + '.' + third + '.')

Запись parts[0][0] — это два обращения подряд: сначала берём слово из списка, потом символ из слова. Читается справа налево, но пишется слева направо.

8.13

Путь в Windows

В Windows полное имя файла состоит из буквы диска, двоеточия и символа \, затем через такой же символ перечисляются подкаталоги, а в конце пишется имя файла: C:\Windows\System32\calc.exe.

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

Формат входных данных
Одна строка — полное имя файла.
Формат выходных данных
Части пути, каждая на отдельной строке.
Ввод
C:\Windows\System32\calc.exe
Вывод
C:
Windows
System32
calc.exe
Подсказка 1

Разделитель здесь задан явно, значит, у split() будет параметр.

Подсказка 2

Одиночная обратная косая черта в кавычках — управляющий символ. Чтобы получить её саму, пишут две.

Разбор
  1. Читаем строку.
  2. Разбиваем её split('\\') — две косые черты в коде означают одну настоящую.
  3. Печатаем части в столбик распаковкой.
Решение
path = input()

# '\\' в коде — это один символ обратной косой черты
parts = path.split('\\')

print(*parts, sep='\n')

Обратная косая черта — вечный источник путаницы: в исходном коде её пишут дважды, а на экране она одна. Проверить себя просто: len('\\') равно единице.

8.14

Столбчатая диаграмма

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

Формат входных данных
Одна строка с числами через пробел.
Формат выходных данных
Для каждого числа — строка из такого количества плюсов.
Ввод
5 3 1 7 10 2
Вывод
+++++
+++
+
+++++++
++++++++++
++
Подсказка 1

Числа приходят одной строкой — их надо разделить.

Подсказка 2

После split() элементы списка — строки, а умножать на строку нельзя: нужен int().

Разбор
  1. Разбиваем строку на список.
  2. Перебираем элементы списка.
  3. Каждый переводим в число и печатаем строку из такого количества плюсов.
Решение
numbers = input().split()

for n in numbers:
    print('+' * int(n))   # после split() элементы — строки, нужен int()

Забытый int() тут не сломает программу молча: '+' * '5' — ошибка, и Python скажет об этом сразу. Это тот редкий случай, когда язык ловит промах за вас.

8.15

Корректный IP-адрес

На вход подаётся строка текста, содержащая 4 целых числа, разделённых точкой. Напишите программу, которая определяет, является ли она корректным IP-адресом.

Адрес корректен, если все четыре числа лежат в диапазоне от 0 до 255 включительно.

Формат входных данных
Одна строка с четырьмя числами через точку.
Формат выходных данных
ДА или НЕТ.
Ввод 1
192.168.0.3
Вывод 1
ДА
Ввод 2
192.168.0.300
Вывод 2
НЕТ
Ввод 3
0.0.0.255
Вывод 3
ДА
Подсказка 1

Разделитель — точка, и её надо указать явно.

Подсказка 2

Проверять надо все четыре числа, а ответ «НЕТ» достаточно получить один раз — это задача на сигнальную метку.

Разбор
  1. Разбиваем строку по точке.
  2. Ставим флажок «пока всё хорошо».
  3. Перебираем части, переводим каждую в число и проверяем границы.
  4. Печатаем ответ по флажку.
Решение
parts = input().split('.')

correct = True
for part in parts:
    number = int(part)
    if number < 0 or number > 255:
        correct = False

if correct:
    print('ДА')
else:
    print('НЕТ')

Флажок нужен именно потому, что печатать ответ внутри цикла нельзя: «ДА» станет известно только после проверки всех четырёх чисел. Тот же приём, что и в задаче про чётные числа на четвёртом занятии.

8.16

Добавить разделитель

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

Формат входных данных
Две строки: текст и разделитель.
Формат выходных данных
Текст с разделителем между символами.
Ввод 1
1234567
*
Вывод 1
1*2*3*4*5*6*7
Ввод 2
qwerty and password
**
Вывод 2
q**w**e**r**t**y** **a**n**d** **p**a**s**s**w**o**r**d
Подсказка 1

Собирает строку из частей метод join(), и вызывается он у разделителя.

Подсказка 2

А части здесь — символы строки. Отдельно разбивать её не нужно: join() работает и со строкой.

Разбор
  1. Читаем текст и разделитель.
  2. Вызываем join() у разделителя, передав ему текст.
  3. Печатаем результат.
Решение
text = input()
separator = input()

# join() вызывается у разделителя, а получает то, что надо склеить
print(separator.join(text))

Обратите внимание на второй пример: пробел — такой же символ, и разделитель встаёт и рядом с ним. Это не ошибка, а точное выполнение условия «между каждым символом».

8.17

Количество совпадающих пар

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

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

3333312343333356733333893333310
Первая тройка составляет пару с каждой из четырёх следующих, вторая — с тремя оставшимися, третья — с двумя, четвёртая — с последней: 4 + 3 + 2 + 1 = 10 пар.
Формат входных данных
Одна строка с числами через пробел.
Формат выходных данных
Одно число — количество пар.
Ввод 1
1 7 5 7 5
Вывод 1
2
Ввод 2
3 3 3 3 3
Вывод 2
10
Ввод 3
8 7 6
Вывод 3
0
Подсказка 1

Пара — это два элемента с разными индексами. Значит, перебирать надо пары индексов.

Подсказка 2

Чтобы не посчитать одну и ту же пару дважды, второй индекс всегда берут больше первого.

Разбор
  1. Разбиваем строку на список.
  2. Внешний цикл идёт по индексу i, внутренний — по j, начиная с i + 1.
  3. Если элементы равны — увеличиваем счётчик.
  4. Печатаем счётчик.
Решение
numbers = input().split()

count = 0
for i in range(len(numbers)):
    for j in range(i + 1, len(numbers)):   # j всегда правее i: пара считается один раз
        if numbers[i] == numbers[j]:
            count += 1

print(count)

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

Итог занятия

Главное с восьмого занятия. append() добавляет один элемент, extend() — все элементы другой последовательности. del удаляет по индексу или срезу, и после каждого удаления индексы сдвигаются. Печатать список можно циклом или распаковкой print(*list, sep=…). split() превращает строку в список строк (даже если это цифры), join() собирает строку обратно и работает только со строками.