Я пытаюсь написать функцию для расчета покерных комбинаций. Для этого мне нужно проверить, сколько существует дубликатов каждого значения карты. Я знаю, что это можно сделать с помощью хэш-карт, но мне было интересно, можно ли это сделать и с помощью какой-то статически выделенной памяти, например. массивы, учитывая, что количество вариантов в перечислении известно во время компиляции.
#[derive(Debug, Clone, PartialEq, Eq)]
enum Value {
Ace,
King,
Queen,
Jack,
Ten,
Nine,
Eight,
Seven,
Six,
Five,
Four,
Three,
Two,
}
P.S. Я почти уверен, что в ржавчине есть функция для взятия вектора или фрагмента и возврата HashMap
, содержащего количество каждого отдельного элемента в нем, например.
let a = vec![1, 2, 1, 3, 2, 4]
let b = a.counts();
let mut c = HashMap<i32, usize> = HashMap::new();
c.insert(1, 2);
c.insert(2, 2);
c.insert(3, 1);
c.insert(4, 1);
assert_eq(b, c);
Однако мне не удалось его найти. Кто-нибудь знает, что это за функция?
Для этого нет встроенной функции, но это легко написать с помощью Iterator::fold:
use std::collections::HashMap;
use std::hash::Hash;
fn counts<T: Eq + Hash>(items: impl IntoIterator<Item = T>) -> HashMap<T, usize> {
items.into_iter().fold(HashMap::new(), |mut counts, i| {
*counts.entry(i).or_default() += 1;
counts
})
}
Он доступен как Itertools::unique().
@ChayimFriedman Думаю, ты имеешь в виду counts
, но да. Это не часть стандартной библиотеки.
@cdhowie, спасибо, я об этом и думал. Честно говоря, я так часто использую itertools, что забываю, что это не часть стандартной библиотеки.
Приведя варианты перечисления к целым числам, эту проблему можно эффективно решить, используя массив со счетчиками вместо хеш-карты: (игровая площадка)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Value {
Ace,
King,
Queen,
Jack,
Ten,
Nine,
Eight,
Seven,
Six,
Five,
Four,
Three,
Two,
}
fn counter<I>(iter: I) -> [u64;13]
where
I: Iterator<Item = Value>
{
let mut count = [0u64;13];
for v in iter {
let i = v as usize;
count[i] += 1;
}
count
}
fn main() {
let a = [Value::Ace, Value::Two, Value::Two];
let b = counter(a.iter().copied());
dbg!(b);
}
Я чувствую, что counter
должен возвращать [usize; 13]
из-за того, что в Rust обычно используются счетчики usize
.
@BallpointBen Только вещи, которые являются индексами памяти, должны быть usize
. При подсчете можно и нужно использовать u32
или u64
, в зависимости от того, будет ли счет очень большим.
@ChayimFriedman А как насчет дженериков Vec::len
, Iterator::count
и <const N: usize>
?
@BallpointBen Vec::len()
возвращает длину данных в памяти. Операции с памятью обычно работают с usize
. Iterator::count()
— это граница, но поскольку это общая функция, размер данных которой невозможно предсказать, usize
в некоторой степени подходит. const N: usize
обычно служит длиной массива.