Генераторы списков и встроенные функции: вопросы для собеседования (часть 3)

List comprehensions, dict comprehensions, map, filter, zip, enumerate — идиоматический Python, который ожидают от аналитика. На собеседовании просят переписать цикл в comprehension, использовать sorted с ключом или объяснить разницу между map и генератором списка. Владение этими конструкциями показывает зрелость как Python-разработчика.

Коллекции и структуры данныхЦиклы и условияИсключения и отладкаРабота с файлами: JSON и CSVФункции и аргументыИтераторы и генераторыNumPy: основыPandas и DataFrameСинтаксис и типы данных

Вопросы 1115 из 20

11В данных пользователей поле города может отсутствовать. Нужно получить множество уникальных городов в нижнем регистре, пропуская отсутствующие значения. Какой вариант подходит?
A`[u['city'].lower() for u in users if u.get('city')]`
B`{u['city'].lower() for u in users if u.get('city')}`
C`set(u['city'].lower() for u in users)`
D`{u['city'] for u in users if u.get('city')}`
Ответ: Множество с `.lower()` и фильтром по непустому полю даёт уникальные города в нижнем регистре без отсутствующих значений.

Конструкция `{u['city'].lower() for u in users if u.get('city')}` использует множество (фигурные скобки без двоеточия), приводит каждый город к нижнему регистру и заранее отбрасывает записи с отсутствующим или пустым `city`. Вариант с квадратными скобками — это список, в нём останутся дубликаты. Вариант `set(u['city'].lower() for u in users)` упадёт на отсутствующих ключах, потому что фильтра нет. Последний вариант сохраняет регистр, поэтому одинаковые города в разном регистре будут считаться разными.

Подробный разбор →
12Есть словарь `code_to_name = {"RU": "Russia", "FR": "France"}`. Нужно получить обратное отображение `name_to_code` (предполагаем, что значения уникальны). Какой вариант корректен?
A`{v: k for k, v in code_to_name.items()}`
B`{k: v for k, v in code_to_name.items()}`
C`dict(code_to_name.items())`
D`list(code_to_name.items())`
Ответ: Через `.items()` удобно взять пары ключ-значение и поменять их местами в dict comprehension.

В выражении `{v: k for k, v in code_to_name.items()}` мы явно меняем местами ключ и значение: новый ключ — это старое значение `v`, а новое значение — старый ключ `k`. Важно, чтобы значения были уникальны, иначе при инвертировании ключи начнут перезаписываться.

Подробный разбор →
13Есть список email `emails = ["a@x.com", "b@y.com", "c@x.com"]`. Нужно получить множество доменов (часть после `@`). Какой вариант корректен?
A`{e.split("@")[0] for e in emails}`
B`{e.split("@")[1] for e in emails}`
C`[e.split("@")[1] for e in emails]`
D`set(emails)`
Ответ: Set comprehension позволяет извлечь домен из каждой строки и автоматически убрать дубликаты.

Выражение `{e.split("@")[1] for e in emails}` берёт часть после `@` для каждого email. Результат — `set`, поэтому повторяющиеся домены (например, `"x.com"`) автоматически схлопываются в один элемент.

Подробный разбор →
14Есть список словарей `users`, где у некоторых пользователей отсутствует email (например, `u.get("email")` возвращает `None`). Нужно получить список email в нижнем регистре, пропуская отсутствующие. Какой вариант обычно наиболее читаемый?
A`list(map(lambda u: u["email"].lower(), filter(lambda u: u.get("email"), users)))`
B`[u["email"].lower() for u in users if u.get("email")]`
C`[u.get("email", "").lower() for u in users if u.get("email") is not None]`
D`{u["email"].lower() for u in users if u.get("email")}`
Ответ: Списочное включение с фильтром компактнее `map()`/`filter()` и читается одной строкой: «возьми email каждого пользователя, у которого он есть».

`[u["email"].lower() for u in users if u.get("email")]` сразу выражает намерение и возвращает список, как требуется. Вариант с `map()` и `filter()` делает то же самое, но требует двух `lambda` и читается тяжелее. Вариант с `u.get("email", "")` пропускает только `None`, но если поле есть и равно пустой строке, фильтр `is not None` оставит её и `.lower()` от `""` даст `""` в итоговом списке. Третий вариант с фигурными скобками без двоеточия даёт `set`, а не список, и порядок теряется.

Подробный разбор →
15Дан список батчей `batches = [[101, 102], [], [103]]`. Что вернёт выражение `[x for batch in batches for x in batch]`?
A`[[101, 102], [], [103]]`
B`[101, 102, [], 103]`
C`[101, 102, 103]`
D`[[101, 102], [103]]`
Ответ: Два `for` в списочном включении эквивалентны вложенным циклам и часто используются для «сплющивания» списка списков.

Конструкция `[x for batch in batches for x in batch]` сначала перебирает каждый `batch`, затем элементы `x` внутри него. Пустой `[]` просто не добавляет элементов в результат, поэтому итог — плоский `[101, 102, 103]`. Порядок `for`-ов важен: внешний цикл должен идти первым, иначе переменная внутреннего цикла не успеет быть определена и интерпретатор выдаст `NameError`. Пустые подсписки никак не нарушают результат, они просто не вкладывают ничего на свой шаг.

Подробный разбор →
1234

Хотите тренировать интерактивно?

В приложении — таймер, прогресс, стрики и 1700+ вопросов по всем темам.

Тренировать Python в Telegram

Другие темы: Python

Коллекции и структуры данныхЦиклы и условияИсключения и отладкаРабота с файлами: JSON и CSVФункции и аргументыИтераторы и генераторыNumPy: основыPandas и DataFrameСинтаксис и типы данных