Python · Синтаксис · Проміжний
collections: Counter, defaultdict, namedtuple
Спеціалізовані типи контейнерів: Counter для підрахунку, defaultdict для згрупованих даних, namedtuple для структурованих записів.
Короткий вступ до теми та пояснення перед вправами (вправи нижче):
deque (з maxlen) та namedtuple
#OrderedDict, ChainMap та вибір правильної колекції
#Вправи:
Використайте `Counter`, щоб порахувати, скільки разів кожне слово з'являється в списку. Поверніть об'єкт Counter.
from collections import Counter
def word_count(words):
# ваш код тут
pass
words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
c = word_count(words)
print(c['apple']) # 3
print(c['banana']) # 2
print(c['grape']) # 0 (Counter повертає 0 для відсутніх ключів)
Рішення
from collections import Counter
def word_count(words):
return Counter(words)
Поверніть 3 найпоширеніші слова в списку слів.
from collections import Counter
def top_three(words):
# ваш код тут
pass
words = ['the', 'cat', 'sat', 'on', 'the', 'mat', 'the', 'cat', 'is', 'fat']
print(top_three(words)) # [('the', 3), ('cat', 2), ('sat', 1)] або подібне
Рішення
from collections import Counter
def top_three(words):
return Counter(words).most_common(3)
Згрупуйте список слів за їх першою літерою за допомогою `defaultdict`. Поверніть словник, де кожен ключ — літера, а значення — список слів.
from collections import defaultdict
def group_by_letter(words):
# ваш код тут
pass
words = ['apple', 'banana', 'avocado', 'blueberry', 'cherry']
result = group_by_letter(words)
print(result['a']) # ['apple', 'avocado']
print(result['b']) # ['banana', 'blueberry']
Рішення
from collections import defaultdict
def group_by_letter(words):
groups = defaultdict(list)
for word in words:
groups[word[0]].append(word)
return dict(groups)
Використайте `defaultdict(int)`, щоб підрахувати частоти літер у рядку. Поверніть defaultdict.
from collections import defaultdict
def letter_freq(s):
# ваш код тут
pass
freq = letter_freq('hello')
print(freq['l']) # 2
print(freq['h']) # 1
print(freq['z']) # 0
Рішення
from collections import defaultdict
def letter_freq(s):
freq = defaultdict(int)
for c in s:
freq[c] += 1
return freq
Використайте `OrderedDict` для створення кешу, що зберігає 3 останні унікальні доданих елементи (схоже на LRU). Реалізуйте методи `add(key, value)` і `get_all()`.
from collections import OrderedDict
class SmallCache:
def __init__(self):
self.cache = OrderedDict()
self.max_size = 3
def add(self, key, value):
# ваш код тут
pass
def get_all(self):
return list(self.cache.items())
c = SmallCache()
c.add('a', 1)
c.add('b', 2)
c.add('c', 3)
c.add('d', 4) # 'a' має бути витіснений
print(c.get_all()) # [('b', 2), ('c', 3), ('d', 4)]
Рішення
from collections import OrderedDict
class SmallCache:
def __init__(self):
self.cache = OrderedDict()
self.max_size = 3
def add(self, key, value):
if key in self.cache:
self.cache.move_to_end(key)
self.cache[key] = value
if len(self.cache) > self.max_size:
self.cache.popitem(last=False) # видалити найстаріший
def get_all(self):
return list(self.cache.items())
Використайте `deque` для реалізації ковзного вікна максимуму: для списку чисел і розміру вікна k поверніть список максимального значення в кожному вікні.
from collections import deque
def sliding_max(nums, k):
# ваш код тут
pass
print(sliding_max([1, 3, -1, -3, 5, 3, 6, 7], 3))
# [3, 3, 5, 5, 6, 7]
Рішення
from collections import deque
def sliding_max(nums, k):
result = []
window = deque() # зберігає індекси
for i, n in enumerate(nums):
while window and nums[window[-1]] <= n:
window.pop()
window.append(i)
if window[0] <= i - k:
window.popleft()
if i >= k - 1:
result.append(nums[window[0]])
return result
Використайте `namedtuple` для створення типу `Point` з полями `x` і `y`. Поверніть функцію, що обчислює відстань між двома точками.
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
def distance(p1, p2):
# ваш код тут
pass
a = Point(0, 0)
b = Point(3, 4)
print(distance(a, b)) # 5.0
Рішення
from collections import namedtuple
import math
Point = namedtuple('Point', ['x', 'y'])
def distance(p1, p2):
return math.sqrt((p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2)
Для двох Counter (частоти слів з двох текстів) поверніть новий Counter з об'єднаними частотами слів.
from collections import Counter
def combine_frequencies(c1, c2):
# ваш код тут
pass
c1 = Counter({'apple': 3, 'banana': 1})
c2 = Counter({'apple': 2, 'cherry': 4})
result = combine_frequencies(c1, c2)
print(result['apple']) # 5
print(result['banana']) # 1
print(result['cherry']) # 4
Рішення
from collections import Counter
def combine_frequencies(c1, c2):
return c1 + c2
Використайте `deque` з `maxlen` для збереження лише останніх N елементів, доданих до потоку. Реалізуйте клас `StreamBuffer` з методами `push(item)` і `get_recent()`.
from collections import deque
class StreamBuffer:
def __init__(self, maxlen):
# ваш код тут
pass
def push(self, item):
# ваш код тут
pass
def get_recent(self):
return list(self.buffer)
buf = StreamBuffer(3)
for x in [1, 2, 3, 4, 5]:
buf.push(x)
print(buf.get_recent()) # [3, 4, 5]
Рішення
from collections import deque
class StreamBuffer:
def __init__(self, maxlen):
self.buffer = deque(maxlen=maxlen)
def push(self, item):
self.buffer.append(item)
def get_recent(self):
return list(self.buffer)
Для списку транзакцій (кожна — словник з 'category' і 'amount') використайте `defaultdict` для обчислення загальної суми за категорією.
from collections import defaultdict
def totals_by_category(transactions):
# ваш код тут
pass
txns = [
{'category': 'food', 'amount': 12.5},
{'category': 'travel', 'amount': 200.0},
{'category': 'food', 'amount': 8.0},
{'category': 'travel', 'amount': 50.0},
{'category': 'books', 'amount': 25.0},
]
result = totals_by_category(txns)
print(result['food']) # 20.5
print(result['travel']) # 250.0
Рішення
from collections import defaultdict
def totals_by_category(transactions):
totals = defaultdict(float)
for t in transactions:
totals[t['category']] += t['amount']
return dict(totals)