Это изменяемая структура словарь (“dictionary” в Python), которая хранит пары “ключ->значение”. В Rust Prelude она не входит, макроса создания не имеет. Поэтому нужно указывать библиотеку явно и явно создавать структуру.
scores.insert(String::from("Gamma"),3);// вставка дважды значений по одному
scores.insert(String::from("Gamma"),6);// ключу сохранит последнее значение
Записывать значение, если у ключа его нет:
scores.entry(String::from("Delta")).or_insert(4);// entry проверяет наличие
// значения, or_insert возвращает mut ссылку на него, либо записывает новое
// значение и возвращает mut ссылку на это значение.
Записывать значение, если ключа нет. Если же у ключа есть значение, модифицировать его:
usestd::collections::HashMap;letmutmap: HashMap<&str,u32>=HashMap::new();map.entry("poneyland")// первое добавление
.and_modify(|e|{*e+=1}).or_insert(42);// добавит ключ "poneyland: 42"
assert_eq!(map["poneyland"],42);map.entry("poneyland")// второе добавление найдёт ключ со значением
.and_modify(|e|{*e+=1})// и модифицирует его
.or_insert(42);assert_eq!(map["poneyland"],43);
Записывать значение, если ключа нет, в виде результата функции. Эта функция получает ссылку на значение ключа key, который передаётся в .entry(key):
Упорядоченная по ключам K структура данных на основе B-дерева.
Ключевые отличия от HashMap:
Свойство
HashMap
BTreeMap
Внутренняя структура
Хэш таблица
Дерево поиска
Упорядоченность
Не гарантированная
Ключи всегда упорядочены
Скорость
O(1)
O(log n)
Требования
Hash + Eq
Ord
Потребление памяти
Выше
Ниже
Применение
Когда нужно сразу сортировать данные:
letmutscores=BTreeMap::new();scores.insert("Charlie",85);scores.insert("Alice",92);scores.insert("Bob",78);// Итерация сразу в отсортированном порядке по ключам
for(name,score)in&scores{println!("{}: {}",name,score);// Alice, Bob, Charlie
}// Получить 1ый и последний элементы
println!("{:?}",scores.first_key_value());// ("Alice", 92)
println!("{:?}",scores.last_key_value());// ("Charlie", 85)
Работа с диапазонами значений:
// Диапазоны заданы кортежами (нижняя_граница, верхняя_граница)
letmutprice_ranges=BTreeMap::new();price_ranges.insert((0,10),"Budget");price_ranges.insert((11,50),"Standard");price_ranges.insert((51,100),"Premium");price_ranges.insert((101,1000),"Luxury");letquery_price=42;// Поиск по диапазонам (линейный в данном случае)
for((low,high),category)in&price_ranges{ifquery_price>=*low&&query_price<=*high{println!("Price ${} is in category: {} (range: {}-{})",query_price,category,low,high);break;}}
useserde_jsonletmutconfig=BTreeMap::new();config.insert("zebra","animal");config.insert("apple","fruit");config.insert("banana","fruit");// сериализация в JSON с порядком элементов
letjson=serde_json::to_string_pretty(&config).unwrap();println!("{}",json);// ключи будут в порядке: apple, banana, zebra
Для небольших коллекций (< 1000 элементов) или когда требуется отсортированный порядок, BTreeMap часто предпочтительнее. Для больших коллекций, где нужна максимальная скорость, а порядок не имеет значения, HashMap обычно лучше.
Оба типа представляют множества для хранения уникальных элементов.
Отличия HashSet и BTreeSet
Множество
HashSet
BTreeSet
Сортировка
Случайный порядок
Да
Сложность алгоритма
O(1) в среднем
O(log n)
Потребление памяти
Выше (hash-таблица)
Ниже
Запросы диапазонов значений
Нет
Да
Типажи
T: Hash + Eq
T: Ord
Работа с HashSet
usestd::collections::HashSet;fnmain(){// Создание
letmutcolors=HashSet::new();// Добавление элеметов
colors.insert("red");colors.insert("green");colors.insert("blue");colors.insert("red");// дубликат - не будет добавлен!
println!("HashSet: {:?}",colors);// порядок произвольный
// Проверка существования элемента
ifcolors.contains("green"){println!("Contains green!");}// Итерация (порядок не гарантирован)
forcolorin&colors{println!("Color: {}",color);}// Удаление элемента
colors.remove("blue");// Объединение двух HashSet
letmutwarm_colors=HashSet::new();warm_colors.insert("red");warm_colors.insert("yellow");warm_colors.insert("orange");letall_colors: HashSet<_>=colors.union(&warm_colors).collect();println!("All colors: {:?}",all_colors);}
Работа с BTreeSet
usestd::collections::BTreeSet;fnmain(){// Создание BTreeSet
letmutnumbers=BTreeSet::new();// Вставка элементов (авто-сортировка!)
numbers.insert(5);numbers.insert(2);numbers.insert(8);numbers.insert(1);numbers.insert(5);// дубликат - не будет добавлен!
println!("BTreeSet: {:?}",numbers);// сортировка всегда: {1, 2, 5, 8}
// Проверка существования элемента
ifnumbers.contains(&2){println!("Contains 2!");}// Итерация по порядку
fornumin&numbers{println!("Number: {}",num);// 1, 2, 5, 8
}// Получить первый и последний элементы
ifletSome(first)=numbers.first(){println!("First element: {}",first);// 1
}ifletSome(last)=numbers.last(){println!("Last element: {}",last);// 8
}// Запрос диапазона значений
letrange: Vec<_>=numbers.range(2..=5).collect();println!("Numbers between 2 and 5: {:?}",range);// [2, 5]
// Удаление элемента
numbers.remove(&5);}
HashSet -> Vector
Простой способ:
usestd::collections::HashSet;letset: HashSet<char>=['a','b','c','d'].into_iter().collect();// Перевод в Vec<char> - расстановка элементов произвольная
letvec: Vec<char>=set.into_iter().collect();println!("Vec: {:?}",vec);// Example: ['c', 'a', 'd', 'b']
Вектор - множество данных одного типа, количество которых можно изменять: добавлять и удалять элементы. Нужен, когда:
требуется собрать набор элементов для обработки в других местах;
нужно выставить элементы в определённом порядке, с добавлением новых элементов в конец;
нужно реализовать стэк;
нужен массив изменяемой величины и расположенный в куче.
Методы
// Задание пустого вектора:
// let mut a test_vector: Vec<i32> = Vec::new();
// Задание вектора со значениями через макрос:
letmuttest_vector=vec![1,2,3,4];test_vector.push(42);// добавить число 42 в конец mut вектора
letSome(last)=test_vector.pop();// удаляет и возвращает последний элемент (возвращает Option<T>)
test_vector.remove(0);// удалить первый элемент =1
foriin&muttest_vector{// пройти вектор как итератор для вывода
*i+=1;// изменять значения при их получении требует делать '*' dereference
println!("{i}");}println!("Vector length: {}",test_vector.len());// количество элементов
Элемент можно получить либо с помощью индекса, либо с помощью безопасного метода get:
letmuttest_vector=vec![1,2,3,4,5];println!("Third element of vector is: {}",&test_vector[2]);// индекс
letthird: Option<&i32>=test_vector.get(2);// безопасный метод get
matchthird{Some(third)=>println!("Third element of vector is: {}",third),None=>println!("There is no third element")}
Разница в способах в реакции на попытку взять несуществующий элемент за пределами вектора. Взятие через индекс приведёт к панике и остановке программы. Взятие с помощью get сопровождается проверкой и обработкой ошибки.
Удаление элемента
Метод .remove(index):
letmutnumbers=vec![1,2,3,4];numbers.remove(1);// удаляет элемент с индексом 1
println!("{:?}",numbers);// [1, 3, 4]
.remove() сдвигает все последующие элементы, что может быть дорого для больших векторов (O(n));
Возвращает удалённый элемент;
Требует mut, так как изменяет вектор;
Индекс должен быть в пределах длины, иначе паника.
Хранение элементов разных типов в векторе
Rust нужно заранее знать при компиляции, сколько нужно выделять памяти под каждый элемент. Если известны заранее все типы для хранения, то можно использовать промежуточный enum:
Смена элементов при сравнении, метод .sort_by() принимает замыкание (closure) для пользовательской сортировки:
number_vector.sort_by(|a,b|b.cmp(a));
|a, b| — это замыкание;
b.cmp(a) возвращает порядок: Ordering::Less, Equal или Greater. Инверсия (b.cmp(a) вместо a.cmp(b)) даёт убывающий порядок.
Альтернатива: .sort_by_key() для сортировки по вычисляемому ключу:
letmutnumbers=vec![3,1,4,1,5];numbers.sort_by_key(|&x|-x);// по убыванию через отрицание
println!("{:?}",numbers);// [5, 4, 3, 1, 1]
Если вернуть Reverse со ссылкой и без *, это приведёт к проблеме с временем жизни.
Сортировка вектора по ключу
usestd::collections::HashSet;fnmain(){letmutvowels=HashSet::new();vowels.insert('e');vowels.insert('a');vowels.insert('i');vowels.insert('o');vowels.insert('u');// Конвертация в Vec и сортировка
letmutvowel_vec: Vec<char>=vowels.into_iter().collect();// Свой порядок сортировки: a, e, i, o, u
letvowel_order=|c: &char|matchc{'a'=>0,'e'=>1,'i'=>2,'o'=>3,'u'=>4,_=>5,};vowel_vec.sort_by_key(vowel_order);println!("Sorted vowels: {:?}",vowel_vec);// ['a', 'e', 'i', 'o', 'u']
}
Дедупликация вектора
Удаление одинаковых элементов в векторе, похоже на работу с HashSet.
lets="aabbccdddeeeeffffeee";letmutchars: Vec<char>=s.chars().collect();// Сначала отсортировать, чтобы собрать одинаковые элементы вместе
chars.sort_unstable();// dedup() удаляет на месте одинаковые СТОЯЩИЕ РЯДОМ в векторе элементы
chars.dedup();// собрать назад в String:
letunique_s: String=chars.into_iter().collect();