Некоторый фон. Существует class Card
, он имеет enum
с именем RANK
и член Rank
типа RANK
. Цель состоит в том, чтобы взять IEnumerable<Card>
и создать словарь, подобный объекту, Key
отредактированный RANK
и Value
d числом такого ранга в аргументированной последовательности.
например. в контексте покера последовательность из пяти карт с четырьмя тузами выдает словарь вариантов {(ACE,4),(someOtherRank,1)}
. Ниже приведена функция, которая у меня есть.
static IReadOnlyDictionary<Card.RANK, int> GetRankDistribution(IEnumerable<Card> hand)
{
var distribution = new Dictionary<Card.RANK, int>(13);
foreach (Card.RANK rank in hand.Select(card => card.Rank))
{
distribution.TryGetValue(rank, out var valueBuffer);
distribution[rank] = valueBuffer + 1;
}
return distribution;
}
Моя проблема в том, что эта функция вызывается чрезмерное количество раз, и, несмотря на то, что словарь имеет оптимальный размер для домена, я не могу придумать, как избежать хеширования дважды для создания объекта (один раз в TryGet и один раз для применить значение, независимо от того, увеличен ли он int()
или функциональный ++
).
В C ++ я мог бы ++dictionary[rank];
в теле цикла. Если Key
отсутствует, он вставляется со стандартным значением Value
, созданным на месте, и возвращается его ссылка (возможный операнд precrement ™).
В Python я мог бы просто return Counter(hand)
, и кто знает, что происходит, но это по крайней мере синтаксически элегантно.
Есть ли способ в C #, учитывая самый примитивный из типов значений, эффективно достичь того, что делает оператор карты C ++ [] (к лучшему или к худшему)?
Если в ответе участвуют наследование и рефакторинг, лично я не считаю его «эффективным», как я его определяю.