Map — это основная структура данных для хранения пар ключ-значение. Изучите мощные возможности Map в Топазе! 🗝️
🌱 Основные концепции Map
Что такое Map?
Map — это ассоциативный массив, который хранит данные в виде пар ключ-значение. Каждый ключ уникален, и значения можно быстро получить через ключи.
// Основное создание и использование Map
function базовыйПримерMap() {
// Создание пустого map
let mut картаБаллов: Map<string, int> = Map::new()
// Вставка значений
картаБаллов.insert("Алиса", 95)
картаБаллов.insert("Боб", 87)
картаБаллов.insert("Чарли", 92)
// Получение значений
match картаБаллов.get("Алиса") { case Some(баллыАлисы) => print!("Баллы Алисы: {}", баллыАлисы), case None => {} }
// Обновление значений
картаБаллов.insert("Алиса", 98) // Перезапись существующего значения
// Итерация по всем парам ключ-значение
for (имя, баллы) in &картаБаллов {
print!("{}: {}", имя, баллы)
}
}
// Создание Map литерала
function примерЛитералаMap() -> Map<string, int> {
map! {
"Математика" => 90,
"Наука" => 85,
"Английский" => 93,
"История" => 88
}
}
// Использование составных типов данных как значений
struct ИнформацияСтудента {
возраст: int,
курс: int,
специальность: string
}
function картаСоставныхДанных() -> Map<string, ИнформацияСтудента> {
let mut картаСтудентов = Map::new()
картаСтудентов.insert("Иван Иванов", ИнформацияСтудента {
возраст: 20,
курс: 2,
специальность: "Информатика".to_string()
})
картаСтудентов.insert("Мария Петрова", ИнформацияСтудента {
возраст: 19,
курс: 1,
специальность: "Математика".to_string()
})
return картаСтудентов
} test {
// Основной тест Map
let mut тестоваяКарта: Map<string, int> = Map::new()
тестоваяКарта.insert("ключ1", 100)
тестоваяКарта.insert("ключ2", 200)
assert тестоваяКарта.get("ключ1") == Some(&100)
assert тестоваяКарта.get("ключ3") == None
assert тестоваяКарта.len() == 2
// Тест литерала Map
let баллыПредметов = примерЛитералаMap()
assert баллыПредметов.get("Математика") == Some(&90)
assert баллыПредметов.len() == 4
// Тест составных данных
let студенты = картаСоставныхДанных()
match студенты.get("Иван Иванов") { case Some(иван) => { assert иван.возраст == 20; assert иван.специальность == "Информатика" }, case None => {} }
}
базовыйПримерMap()
let картаПредметов = примерЛитералаMap()
print!("Количество предметов: {}", картаПредметов.len())
let картаСтудентов = картаСоставныхДанных()
for (имя, информация) in &картаСтудентов {
print!("{}: {} лет, {} курс, специальность {}", имя, информация.возраст, информация.курс, информация.специальность)
}
Основные особенности Map
- Уникальные ключи: Каждый ключ должен быть уникальным в карте
- Быстрый поиск: O(1) средняя временная сложность для получения значений
- Динамический размер: Размер может изменяться во время выполнения
- Типобезопасность: Типы ключей и значений определяются во время компиляции
🛠️ Основные операции Map
Создание, вставка и получение
// Различные способы создания Map
function способыСозданияMap() {
// 1. Создание пустой карты
let mut пустаяКарта: Map<int, string> = Map::new()
// 2. Создание с заданной емкостью
let mut картаСЕмкостью: Map<string, int> = Map::with_capacity(100)
// 3. Инициализация со значениями по умолчанию
let mut картаПоУмолчанию = Map::new()
картаПоУмолчанию.insert("ключПоУмолчанию", "значениеПоУмолчанию")
// 4. Клонирование из другой карты
let клонированнаяКарта = картаПоУмолчанию.clone()
print!("Размер пустой карты: {}", пустаяКарта.len())
print!("Размер клонированной карты: {}", клонированнаяКарта.len())
}
// Вставка и обновление значений
function операцииВставкиЗначений() {
let mut картаСчетчиков: Map<string, int> = Map::new()
// Вставка новых значений
картаСчетчиков.insert("яблоко", 5)
картаСчетчиков.insert("банан", 3)
// Обновление существующих значений
картаСчетчиков.insert("яблоко", 8) // Изменение 5 -> 8
// Использование Entry API (более эффективно)
картаСчетчиков.entry("апельсин").or_insert(0) // Вставить 0, если ключа нет
картаСчетчиков.entry("яблоко").and_modify(|значение| *значение += 2) // Добавить 2 к существующему
// Использование возвращаемого значения insert
match картаСчетчиков.insert("виноград", 7) { case Some(предыдущееЗначение) => print!("Предыдущее значение винограда: {}", предыдущееЗначение), case None => print!("виноград — новый ключ.") }
for (фрукт, количество) in &картаСчетчиков {
print!("{}: {} штук", фрукт, количество)
}
}
// Получение значений и проверка существования
function операцииПолученияЗначений() {
let картаИнвентаря = map! {
"Яблоко" => 50,
"Банан" => 30,
"Апельсин" => 25,
"Виноград" => 40
}
// Получение значения с помощью get
match картаИнвентаря.get("Яблоко") {
case Some(количество) => print!("Инвентарь яблок: {} штук", количество),
case None => print!("Нет яблок в инвентаре")
}
// Проверка существования ключа с помощью contains_key
if картаИнвентаря.contains_key("Клубника") {
print!("Клубника доступна")
} else {
print!("Нет клубники в инвентаре")
}
// Получение изменяемой ссылки с помощью get_mut
let mut изменяемаяКартаИнвентаря = картаИнвентаря.clone()
match изменяемаяКартаИнвентаря.get_mut("Банан") { case Some(инвентарьБанана) => { *инвентарьБанана -= 10; print!("Инвентарь бананов после продажи: {} штук", *инвентарьБанана) }, case None => {} }
// Получение со значением по умолчанию
let инвентарьКиви = изменяемаяКартаИнвентаря.get("Киви").unwrap_or(&0)
print!("Инвентарь киви: {} штук", инвентарьКиви)
}
// Удаление значений
function операцииУдаленияЗначений() {
let mut временнаяКарта = map! {
"временный1" => "значение1",
"временный2" => "значение2",
"временный3" => "значение3",
"сохранить" => "важноеЗначение"
}
print!("Размер до удаления: {}", временнаяКарта.len())
// Удаление конкретного ключа
match временнаяКарта.remove("временный1") { case Some(удаленноеЗначение) => print!("Удаленное значение: {}", удаленноеЗначение), case None => {} }
// Условное удаление
временнаяКарта.retain(|ключ, _| !ключ.starts_with("временный"))
print!("Размер после удаления: {}", временнаяКарта.len())
print!("Оставшиеся ключи: {:?}", временнаяКарта.keys().collect::<Vec<_>>())
// Удаление всех элементов
временнаяКарта.clear()
print!("Размер после очистки всех: {}", временнаяКарта.len())
} test {
// Тест создания карты
let mut тестоваяКарта: Map<string, int> = Map::new()
assert тестоваяКарта.is_empty()
// Тест вставки
тестоваяКарта.insert("ключ1", 100)
тестоваяКарта.insert("ключ2", 200)
assert тестоваяКарта.len() == 2
// Тест получения
assert тестоваяКарта.get("ключ1") == Some(&100)
assert тестоваяКарта.contains_key("ключ2")
assert !тестоваяКарта.contains_key("ключ3")
// Тест обновления
let предыдущееЗначение = тестоваяКарта.insert("ключ1", 150)
assert предыдущееЗначение == Some(100)
assert тестоваяКарта.get("ключ1") == Some(&150)
// Тест удаления
let удаленноеЗначение = тестоваяКарта.remove("ключ2")
assert удаленноеЗначение == Some(200)
assert тестоваяКарта.len() == 1
}
способыСозданияMap()
операцииВставкиЗначений()
операцииПолученияЗначений()
операцииУдаленияЗначений()
Итерация и преобразование
// Методы итерации по Map
function методыИтерацииMap() {
let картаБаллов = map! {
"Математика" => 95,
"Наука" => 88,
"Английский" => 92,
"История" => 85
}
// 1. Итерация по парам ключ-значение
print!("=== Итерация по парам ключ-значение ===")
for (предмет, баллы) in &картаБаллов {
print!("{}: {} баллов", предмет, баллы)
}
// 2. Итерация только по ключам
print!("=== Итерация только по ключам ===")
for предмет in картаБаллов.keys() {
print!("Предмет: {}", предмет)
}
// 3. Итерация только по значениям
print!("=== Итерация только по значениям ===")
for баллы in картаБаллов.values() {
print!("Баллы: {} баллов", баллы)
}
// 4. Итерация по изменяемым значениям (корректировка баллов)
let mut изменяемаяКартаБаллов = картаБаллов.clone()
for (_, баллы) in &mut изменяемаяКартаБаллов {
*баллы += 5 // Добавить 5 баллов ко всем оценкам
}
print!("=== Скорректированные баллы ===")
for (предмет, баллы) in &изменяемаяКартаБаллов {
print!("{}: {} баллов", предмет, баллы)
}
}
// Преобразование и фильтрация Map
function преобразованиеФильтрацияMap() {
let исходнаяКарта = map! {
"яблоко" => 10,
"банан" => 5,
"апельсин" => 15,
"виноград" => 8,
"киви" => 12
}
// Преобразование карты в вектор
let векторКлючЗначение: Vec<(string, int)> = исходнаяКарта.iter()
.map(|(ключ, значение)| (ключ.clone(), *значение))
.collect()
print!("Вектор ключ-значение: {:?}", векторКлючЗначение)
// Фильтрация элементов по условию
let дорогиеФрукты: Map<string, int> = исходнаяКарта.iter()
.filter(|(_, &цена)| цена >= 10)
.map(|(ключ, значение)| (ключ.clone(), *значение))
.collect()
print!("Фрукты >= 10: {:?}", дорогиеФрукты)
// Преобразование значений
let ценыСоСкидкой: Map<string, int> = исходнаяКарта.iter()
.map(|(ключ, значение)| (ключ.clone(), значение * 90 / 100)) // 10% скидка
.collect()
print!("Цены со скидкой: {:?}", ценыСоСкидкой)
// Преобразование ключей
let картаЗаглавныхКлючей: Map<string, int> = исходнаяКарта.iter()
.map(|(ключ, значение)| (ключ.to_uppercase(), *значение))
.collect()
print!("Заглавные ключи: {:?}", картаЗаглавныхКлючей)
}
// Агрегация и статистика Map
function агрегацияСтатистикаMap() {
let данныеПродаж = map! {
"Январь" => 120,
"Февраль" => 135,
"Март" => 98,
"Апрель" => 156,
"Май" => 189,
"Июнь" => 143
}
// Общие продажи
let общиеПродажи: int = данныеПродаж.values().sum()
print!("Общие продажи: {}", общиеПродажи)
// Средние продажи
let среднийОбъемПродаж = общиеПродажи as f64 / данныеПродаж.len() as f64
print!("Средние продажи: {:.2}", среднийОбъемПродаж)
// Максимальные/минимальные продажи
match данныеПродаж.values().max() { case Some(максимальныеПродажи) => print!("Максимальные продажи: {}", максимальныеПродажи), case None => {} }
match данныеПродаж.values().min() { case Some(минимальныеПродажи) => print!("Минимальные продажи: {}", минимальныеПродажи), case None => {} }
// Количество по конкретному условию
let месяцевДостиженияЦели = данныеПродаж.values()
.filter(|&&продажи| продажи >= 140)
.count()
print!("Месяцев достижения цели (140): {}", месяцевДостиженияЦели)
// Поиск месяца с лучшими показателями
match данныеПродаж.iter().max_by_key(|(_, &продажи)| продажи) { case Some((лучшийМесяц, лучшиеПоказатели)) => print!("Лучшие показатели: {} месяц с {} единицами", лучшийМесяц, лучшиеПоказатели), case None => {} }
} test {
// Тест итерации
let тестоваяКарта = map! {
"A" => 1,
"B" => 2,
"C" => 3
}
let mut ключи = Vec::new()
for ключ in тестоваяКарта.keys() {
ключи.push(ключ.clone())
}
ключи.sort()
assert ключи == vec!["A", "B", "C"]
// Тест преобразования
let удвоеннаяКарта: Map<string, int> = тестоваяКарта.iter()
.map(|(ключ, значение)| (ключ.clone(), значение * 2))
.collect()
assert удвоеннаяКарта.get("A") == Some(&2)
assert удвоеннаяКарта.get("B") == Some(&4)
// Тест фильтрации
let картаБольшихЗначений: Map<string, int> = тестоваяКарта.iter()
.filter(|(_, &значение)| значение > 1)
.map(|(ключ, значение)| (ключ.clone(), *значение))
.collect()
assert картаБольшихЗначений.len() == 2
assert !картаБольшихЗначений.contains_key("A")
}
методыИтерацииMap()
преобразованиеФильтрацияMap()
агрегацияСтатистикаMap()
🚀 Продвинутое использование Map
Entry API и эффективные паттерны
// Использование Entry API
function использованиеEntryAPI() {
let mut картаКоличестваСлов: Map<string, int> = Map::new()
let текст = "привет мир привет rust мир rust программирование"
// Подсчет слов (используя Entry API)
for слово in текст.split_whitespace() {
*картаКоличестваСлов.entry(слово.to_string()).or_insert(0) += 1
}
print!("=== Количество слов ===")
for (слово, количество) in &картаКоличестваСлов {
print!("{}: {} раз", слово, количество)
}
// Сложные паттерны Entry
let mut картаГрупп: Map<string, Vec<int>> = Map::new()
let данные = vec![
("ГруппаA", 10), ("ГруппаB", 20), ("ГруппаA", 15),
("ГруппаC", 5), ("ГруппаB", 25), ("ГруппаA", 30)
]
for (группа, значение) in данные {
картаГрупп.entry(группа.to_string())
.or_insert(Vec::new())
.push(значение)
}
print!("=== Групповые данные ===")
for (группа, значения) in &картаГрупп {
print!("{}: {:?}", группа, значения)
}
}
// Вложенная структура карт
function вложеннаяСтруктураКарт() {
// Студент -> Предмет -> Балл
let mut журналОценок: Map<string, Map<string, int>> = Map::new()
// Функция ввода оценки
let mut вводОценки = |студент: &str, предмет: &str, балл: int| {
журналОценок.entry(студент.to_string())
.or_insert(Map::new())
.insert(предмет.to_string(), балл)
}
// Ввод данных
вводОценки("Иван Петров", "Математика", 95)
вводОценки("Иван Петров", "Наука", 88)
вводОценки("Иван Петров", "Английский", 92)
вводОценки("Мария Иванова", "Математика", 98)
вводОценки("Мария Иванова", "Наука", 94)
вводОценки("Мария Иванова", "Английский", 89)
// Запрос оценок
for (студент, картаПредметов) in &журналОценок {
print!("=== Оценки {} ===", студент)
let mut общийБалл = 0
let mut количествоПредметов = 0
for (предмет, балл) in картаПредметов {
print!(" {}: {} баллов", предмет, балл)
общийБалл += балл
количествоПредметов += 1
}
let средний = if количествоПредметов > 0 { общийБалл as f64 / количествоПредметов as f64 } else { 0.0 }
print!(" Средний: {:.1} баллов", средний)
}
}
// Слияние и объединение карт
function слияниеОбъединениеКарт() {
let инвентарьA = map! {
"Яблоко" => 50,
"Банан" => 30,
"Апельсин" => 20
}
let инвентарьB = map! {
"Банан" => 25, // Дублирующий ключ
"Виноград" => 40,
"Киви" => 15
}
// 1. Простое слияние (B имеет приоритет)
let mut объединенныйИнвентарь = инвентарьA.clone()
for (фрукт, количество) in инвентарьB.iter() {
объединенныйИнвентарь.insert(фрукт.clone(), *количество)
}
print!("=== Простое слияние (приоритет B) ===")
for (фрукт, количество) in &объединенныйИнвентарь {
print!("{}: {} штук", фрукт, количество)
}
// 2. Слияние сумм значений
let mut суммированныйИнвентарь = инвентарьA.clone()
for (фрукт, количество) in инвентарьB.iter() {
*суммированныйИнвентарь.entry(фрукт.clone()).or_insert(0) += количество
}
print!("=== Слияние сумм значений ===")
for (фрукт, количество) in &суммированныйИнвентарь {
print!("{}: {} штук", фрукт, количество)
}
// 3. Слияние максимальных значений
let mut максИнвентарь = инвентарьA.clone()
for (фрукт, количество) in инвентарьB.iter() {
максИнвентарь.entry(фрукт.clone())
.and_modify(|существующееКоличество| *существующееКоличество = (*существующееКоличество).max(*количество))
.or_insert(*количество)
}
print!("=== Слияние максимальных значений ===")
for (фрукт, количество) in &максИнвентарь {
print!("{}: {} штук", фрукт, количество)
}
} test {
// Тест Entry API
let mut счетчик: Map<string, int> = Map::new()
// Вставка нового ключа
счетчик.entry("новыйКлюч".to_string()).or_insert(1)
assert счетчик.get("новыйКлюч") == Some(&1)
// Изменение существующего ключа
*счетчик.entry("новыйКлюч".to_string()).or_insert(0) += 5
assert счетчик.get("новыйКлюч") == Some(&6)
// Тест вложенной карты
let mut вложеннаяКарта: Map<string, Map<string, int>> = Map::new()
вложеннаяКарта.entry("внешнийКлюч".to_string())
.or_insert(Map::new())
.insert("внутреннийКлюч".to_string(), 100)
assert вложеннаяКарта.get("внешнийКлюч").unwrap().get("внутреннийКлюч") == Some(&100)
}
использованиеEntryAPI()
вложеннаяСтруктураКарт()
слияниеОбъединениеКарт()
Оптимизация производительности и управление памятью
// Управление емкостью и оптимизация производительности
function оптимизацияПроизводительности() {
// 1. Установка подходящей начальной емкости
let mut большаяКарта: Map<int, string> = Map::with_capacity(10000)
print!("Начальная емкость: {}", большаяКарта.capacity())
// Вставка большого количества данных
for i in 0..5000 {
большаяКарта.insert(i, format!("значение{}", i))
}
print!("После вставки - длина: {}, емкость: {}", большаяКарта.len(), большаяКарта.capacity())
// 2. Сокращение ненужной емкости
большаяКарта.shrink_to_fit()
print!("После сокращения емкости: {}", большаяКарта.capacity())
// 3. Резервирование места
большаяКарта.reserve(2000)
print!("После резервирования емкости: {}", большаяКарта.capacity())
}
// Эффективные типы ключей
function эффективныеТипыКлючей() {
// Пример сравнения производительности строковых ключей vs целочисленных ключей
// Целочисленные ключи (более эффективные)
let mut картаЦелочисленныхКлючей: Map<u32, string> = Map::new()
for i in 0..1000 {
картаЦелочисленныхКлючей.insert(i, format!("данные{}", i))
}
// Строковые ключи (более высокая стоимость хеширования)
let mut картаСтроковыхКлючей: Map<string, string> = Map::new()
for i in 0..1000 {
картаСтроковыхКлючей.insert(format!("ключ{}", i), format!("данные{}", i))
}
print!("Размер карты целочисленных ключей: {}", картаЦелочисленныхКлючей.len())
print!("Размер карты строковых ключей: {}", картаСтроковыхКлючей.len())
// Небольшие строки хранятся в стеке (эффективно)
let mut картаФиксированныхСтрок: Map<&'static str, int> = map! {
"Красный" => 1,
"Синий" => 2,
"Зеленый" => 3,
"Желтый" => 4
}
print!("Карта фиксированных строк: {:?}", картаФиксированныхСтрок)
}
// Использование пользовательской хеш-функции
use std::collections::hash_map::DefaultHasher
use std::hash::{Hash, Hasher}
struct ПользовательскийКлюч {
id: u32,
name: string
}
impl Hash for ПользовательскийКлюч {
function hash<H: Hasher>(&self, state: &mut H) {
// Использовать только ID для хеша (игнорировать имя)
self.id.hash(state)
}
}
impl PartialEq for ПользовательскийКлюч {
function eq(&self, other: &Self) -> bool {
self.id == other.id // Равенство только по ID
}
}
impl Eq for ПользовательскийКлюч {}
function примерПользовательскогоХеша() {
let mut пользовательскаяКарта: Map<ПользовательскийКлюч, string> = Map::new()
let ключ1 = ПользовательскийКлюч { id: 1, name: "первый".to_string() }
let ключ2 = ПользовательскийКлюч { id: 1, name: "другое_имя".to_string() } // Тот же ID
пользовательскаяКарта.insert(ключ1, "значение1".to_string())
// ключ2 рассматривается как тот же ключ, что и ключ1, потому что у них одинаковый ID
match пользовательскаяКарта.get(&ключ2) { case Some(значение) => print!("Значение, полученное с пользовательским ключом: {}", значение), case None => {} }
} test {
// Тест управления емкостью
let mut тестоваяКарта: Map<int, string> = Map::with_capacity(5)
assert тестоваяКарта.capacity() >= 5
assert тестоваяКарта.is_empty()
// Тест автоматического расширения при превышении емкости
for i in 0..<10 {
тестоваяКарта.insert(i, format!("значение{}", i))
}
assert тестоваяКарта.len() == 10
assert тестоваяКарта.capacity() >= 10
}
оптимизацияПроизводительности()
эффективныеТипыКлючей()
примерПользовательскогоХеша()
🎯 Практические паттерны Map
Кеш и мемоизация
// Простая реализация кеша
struct Кеш<K, V>
where
K: Hash + Eq + Clone,
V: Clone
{
данные: Map<K, V>,
максимальныйРазмер: usize
}
impl<K, V> Кеш<K, V>
where
K: Hash + Eq + Clone,
V: Clone
{
function new(максимальныйРазмер: usize) -> Self {
Кеш {
данные: Map::with_capacity(максимальныйРазмер),
максимальныйРазмер
}
}
function get(&self, ключ: &K) -> Option<&V> {
self.данные.get(ключ)
}
function put(&mut self, ключ: K, значение: V) {
if self.данные.len() >= self.максимальныйРазмер {
// Простой LRU: удалить первый ключ
match self.данные.keys().next().cloned() { case Some(первыйКлюч) => { self.данные.remove(&первыйКлюч) }, case None => {} }
}
self.данные.insert(ключ, значение)
}
function contains_key(&self, ключ: &K) -> bool {
self.данные.contains_key(ключ)
}
function clear(&mut self) {
self.данные.clear()
}
}
// Реализация мемоизации
function примерМемоизации() {
let mut кешФибоначчи: Map<u32, u64> = Map::new()
function фибоначчи(n: u32, кеш: &mut Map<u32, u64>) -> u64 {
match кеш.get(&n) { case Some(&результат) => return результат, case None => {} }
let результат = match n {
case 0 => 0,
case 1 => 1,
case _ => фибоначчи(n - 1, кеш) + фибоначчи(n - 2, кеш)
}
кеш.insert(n, результат)
результат
}
// Вычисление последовательности Фибоначчи
for i in 0..15 {
let значение = фибоначчи(i, &mut кешФибоначчи)
print!("F({}) = {}", i, значение)
}
print!("Размер кеша: {}", кешФибоначчи.len())
}
// Симуляция веб-кеша запросов
function симуляцияВебКеша() {
let mut кешОтветов: Кеш<string, string> = Кеш::new(5)
function симуляцияВебЗапроса(url: &str, кеш: &mut Кеш<string, string>) -> string {
match кеш.get(&url.to_string()) { case Some(кешированныйОтвет) => { print!("Попадание в кеш: {}", url); return кешированныйОтвет.clone() }, case None => {} }
// Симуляция фактического запроса (с задержкой)
print!("Фактический запрос: {}", url)
let ответ = format!("Данные ответа из {}", url)
кеш.put(url.to_string(), ответ.clone())
ответ
}
// Симуляция запросов
let urls = vec![
"https://api.example.com/users",
"https://api.example.com/posts",
"https://api.example.com/users", // Попадание в кеш
"https://api.example.com/comments",
"https://api.example.com/posts", // Попадание в кеш
]
for url in urls {
let ответ = симуляцияВебЗапроса(url, &mut кешОтветов)
print!("Ответ: {}", ответ)
}
} test {
// Тест кеша
let mut тестовыйКеш: Кеш<string, int> = Кеш::new(3)
тестовыйКеш.put("ключ1".to_string(), 100)
тестовыйКеш.put("ключ2".to_string(), 200)
тестовыйКеш.put("ключ3".to_string(), 300)
assert тестовыйКеш.get(&"ключ1".to_string()) == Some(&100)
assert тестовыйКеш.contains_key(&"ключ2".to_string())
// Тест поведения LRU при превышении емкости
тестовыйКеш.put("ключ4".to_string(), 400)
// Первый ключ должен быть удален
assert тестовыйКеш.get(&"ключ4".to_string()) == Some(&400)
}
примерМемоизации()
симуляцияВебКеша()
Индексирование и группировка
// Индексирование данных
struct Пользователь {
id: u32,
имя: string,
возраст: u32,
отдел: string
}
function индексированиеДанных() {
let пользователи = vec![
Пользователь { id: 1, имя: "Иван Петров".to_string(), возраст: 28, отдел: "Разработка".to_string() },
Пользователь { id: 2, имя: "Мария Иванова".to_string(), возраст: 32, отдел: "Дизайн".to_string() },
Пользователь { id: 3, имя: "Алексей Сидоров".to_string(), возраст: 25, отдел: "Разработка".to_string() },
Пользователь { id: 4, имя: "Елена Смирнова".to_string(), возраст: 29, отдел: "Маркетинг".to_string() },
]
// Индексирование по ID
let индексID: Map<u32, &Пользователь> = пользователи.iter()
.map(|пользователь| (пользователь.id, пользователь))
.collect()
// Индексирование по имени
let индексИмен: Map<string, &Пользователь> = пользователи.iter()
.map(|пользователь| (пользователь.имя.clone(), пользователь))
.collect()
// Группировка по отделам
let mut группыОтделов: Map<string, Vec<&Пользователь>> = Map::new()
for пользователь in &пользователи {
группыОтделов.entry(пользователь.отдел.clone())
.or_insert(Vec::new())
.push(пользователь)
}
// Примеры использования индексов
match индексID.get(&2) { case Some(пользователь) => print!("Пользователь с ID 2: {}", пользователь.имя), case None => {} }
match индексИмен.get("Алексей Сидоров") { case Some(пользователь) => print!("Отдел Алексея Сидорова: {}", пользователь.отдел), case None => {} }
// Вывод результатов группировки
for (отдел, участники) in &группыОтделов {
print!("=== {} ===", отдел)
for пользователь in участники {
print!(" {} ({} лет)", пользователь.имя, пользователь.возраст)
}
}
}
// Система мультииндексирования
struct МультиИндекс<T> {
данные: Vec<T>
}
impl МультиИндекс<Пользователь> {
function new(данные: Vec<Пользователь>) -> Self {
МультиИндекс { данные }
}
function найтиПоID(&self, id: u32) -> Option<&Пользователь> {
self.данные.iter().find(|пользователь| пользователь.id == id)
}
function найтиПоОтделу(&self, отдел: &str) -> Vec<&Пользователь> {
self.данные.iter()
.filter(|пользователь| пользователь.отдел == отдел)
.collect()
}
function найтиПоДиапазонуВозраста(&self, минВозраст: u32, максВозраст: u32) -> Vec<&Пользователь> {
self.данные.iter()
.filter(|пользователь| пользователь.возраст >= минВозраст && пользователь.возраст <= максВозраст)
.collect()
}
function статистика(&self) -> Map<string, u32> {
let mut картаСтатистики = Map::new()
// Количество участников по отделам
let mut количествоПоОтделам: Map<string, u32> = Map::new()
for пользователь in &self.данные {
*количествоПоОтделам.entry(пользователь.отдел.clone()).or_insert(0) += 1
}
// Средний возраст
let общийВозраст: u32 = self.данные.iter().map(|пользователь| пользователь.возраст).sum()
let среднийВозраст = if !self.данные.is_empty() {
общийВозраст / self.данные.len() as u32
} else { 0 }
картаСтатистики.insert("общееКоличествоУчастников".to_string(), self.данные.len() as u32)
картаСтатистики.insert("среднийВозраст".to_string(), среднийВозраст)
for (отдел, количество) in количествоПоОтделам {
картаСтатистики.insert(format!("{}_участники", отдел), количество)
}
картаСтатистики
}
}
function примерМультиИндекса() {
let данныеПользователей = vec![
Пользователь { id: 1, имя: "Иван Петров".to_string(), возраст: 28, отдел: "Разработка".to_string() },
Пользователь { id: 2, имя: "Мария Иванова".to_string(), возраст: 32, отдел: "Дизайн".to_string() },
Пользователь { id: 3, имя: "Алексей Сидоров".to_string(), возраст: 25, отдел: "Разработка".to_string() },
Пользователь { id: 4, имя: "Елена Смирнова".to_string(), возраст: 29, отдел: "Маркетинг".to_string() },
]
let индекс = МультиИндекс::new(данныеПользователей)
// Различные поиски
match индекс.найтиПоID(3) { case Some(пользователь) => print!("ID 3: {}", пользователь.имя), case None => {} }
let участникиРазработки = индекс.найтиПоОтделу("Разработка")
print!("Участники разработки: {:?}", участникиРазработки.iter().map(|u| &u.имя).collect::<Vec<_>>())
let молодыеСотрудники = индекс.найтиПоДиапазонуВозраста(25, 30)
print!("25-30 лет: {:?}", молодыеСотрудники.iter().map(|u| &u.имя).collect::<Vec<_>>())
// Вывод статистики
let статистика = индекс.статистика()
for (элемент, значение) in &статистика {
print!("{}: {}", элемент, значение)
}
} test {
// Тест индексирования
let тестовыеПользователи = vec![
Пользователь { id: 1, имя: "Тест1".to_string(), возраст: 25, отдел: "КомандаA".to_string() },
Пользователь { id: 2, имя: "Тест2".to_string(), возраст: 30, отдел: "КомандаB".to_string() },
]
let картаID: Map<u32, &Пользователь> = тестовыеПользователи.iter()
.map(|u| (u.id, u))
.collect()
assert картаID.get(&1).unwrap().имя == "Тест1"
assert картаID.get(&2).unwrap().отдел == "КомандаB"
// Тест мультииндекса
let индекс = МультиИндекс::new(тестовыеПользователи)
assert индекс.найтиПоID(1).is_some()
assert индекс.найтиПоОтделу("КомандаA").len() == 1
assert индекс.найтиПоДиапазонуВозраста(25, 35).len() == 2
}
индексированиеДанных()
примерМультиИндекса()
✅ Освоение Map
Map — одна из самых полезных структур данных в Топазе:
✅ Когда использовать Map:
- Хранение данных ключ-значение
- Когда нужен быстрый поиск
- Индексирование данных и группировка
- Реализация кеша и мемоизации
⚠️ Соображения:
- Выбор подходящих типов ключей (учет производительности хеширования)
- Управление использованием памяти (для больших наборов данных)
- Учет параллелизма (в многопоточных средах)
- Обеспечение неизменности ключей
🚀 Преимущества Map в Топазе:
- Гарантия типобезопасности
- Эффективные алгоритмы хеширования
- Гибкий API
Entry - Безопасное управление памятью
Испытайте эффективное управление данными с Map! 🗝️✨