Подсчитайте количество вхождений каждого варианта перечисления

Я пытаюсь написать функцию для расчета покерных комбинаций. Для этого мне нужно проверить, сколько существует дубликатов каждого значения карты. Я знаю, что это можно сделать с помощью хэш-карт, но мне было интересно, можно ли это сделать и с помощью какой-то статически выделенной памяти, например. массивы, учитывая, что количество вариантов в перечислении известно во время компиляции.

#[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);

Однако мне не удалось его найти. Кто-нибудь знает, что это за функция?

Функция, которую вы ищете
true equals false 24.03.2024 16:35
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
1
66
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Для этого нет встроенной функции, но это легко написать с помощью 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().

Chayim Friedman 24.03.2024 22:06

@ChayimFriedman Думаю, ты имеешь в виду counts, но да. Это не часть стандартной библиотеки.

cdhowie 24.03.2024 22:17

@cdhowie, спасибо, я об этом и думал. Честно говоря, я так часто использую itertools, что забываю, что это не часть стандартной библиотеки.

Pioneer_11 25.03.2024 18:54
Ответ принят как подходящий

Приведя варианты перечисления к целым числам, эту проблему можно эффективно решить, используя массив со счетчиками вместо хеш-карты: (игровая площадка)

#[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 25.03.2024 04:24

@BallpointBen Только вещи, которые являются индексами памяти, должны быть usize. При подсчете можно и нужно использовать u32 или u64, в зависимости от того, будет ли счет очень большим.

Chayim Friedman 25.03.2024 11:30

@ChayimFriedman А как насчет дженериков Vec::len, Iterator::count и <const N: usize>?

BallpointBen 25.03.2024 15:06

@BallpointBen Vec::len() возвращает длину данных в памяти. Операции с памятью обычно работают с usize. Iterator::count() — это граница, но поскольку это общая функция, размер данных которой невозможно предсказать, usize в некоторой степени подходит. const N: usize обычно служит длиной массива.

Chayim Friedman 25.03.2024 15:11

Другие вопросы по теме