Python 中 C# 或 .NET 中的 `collection.Counter` 等效项

问题描述 投票:0回答:2

我在leetcode上解决一些问题,在用python解决问题时我经常不得不使用python的

collections.Counter
对象。

当我开始用 C# 解决同样的问题时,我找不到等效的方法或类。

我只是想知道有没有?

编辑

collections.Counter

的解释

collections.Counter
接受一个 iterable 并返回一个 hash-map,其中键是原始 iterable 的所有唯一元素,对应的值是该 key 在原始 iterable 中出现的次数

python c# dictionary hashmap counter
2个回答
1
投票

这是一个真正快速实现的类,它可以完成您正在考虑的事情。请随意添加一些额外的功能:

public class CountedCollection<T> : IEnumerable<KeyValuePair<T, int>>
{
    private readonly Dictionary<T, int> _countDictionary;

    public CountedCollection()
    {
        if (!typeof(IEquatable<T>).IsAssignableFrom(typeof(T)))
        {
            throw new ArgumentException($"The type {typeof(T).Name} must implement IEquatable of <{typeof(T).Name}> to be usable with CountedCollection");
        }
        _countDictionary = new Dictionary<T, int>();
    }

    public CountedCollection(IEqualityComparer<T> comparer)
    {
        _countDictionary = new Dictionary<T, int>(comparer);
    }

    public void Add(T item)
    {
        ++TotalCount;
        if (_countDictionary.TryGetValue(item, out var curCount))
        {
            _countDictionary[item] = ++curCount;
        }
        else
        {
            _countDictionary.Add(item, 1);
        }
    }

    public void Add (IEnumerable<T> items)
    {
        foreach (var item in items)
        {
            Add(item);
        }
    }

    public int TotalCount { get; private set; } = 0;
    public int DistinctCount => _countDictionary.Count;

    public IEnumerator<KeyValuePair<T, int>> GetEnumerator()
    {
        foreach (var item in _countDictionary)
        {
            yield return item;
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

测试非常简单。

它实现了“集合初始化模式”,并且可以使用现有集合进行初始化,因此这两者都可以工作(第二个使用整数数组来初始化它):

var dict1 = new CountedCollection<string> { "abc", "xyz", "abc", "123" };
var dict2 = new CountedCollection<int> { new[] { 34, 12, 65, 12, 101 } };

该类提供了两个构造函数。如果

T
未实现
IEquatable<T>
,那么您可以提供自己的
IEqualityComparer<T>
实现。这还允许您对实例进行独立于大小写的计数。例如:

var dict3 = new CountedCollection<string>(StringComparer.OrdinalIgnoreCase) 
{ 
    "abc", 
    "xyz", 
    "ABC", 
    "123", 
    "Xyz"
};

该代码将显示两个“abc”实例和两个“xyz”实例。

因为你可以自带

IEqualityComparer<T>
T
不受实现
IEquatable<T>
的限制,如果
ArgumentException
无法实现
T
,第一个构造函数将抛出
IEquatable<T>
(事物必须以某种方式具有可比性以确保相等) ).

例如,这会抛出:

var dict4 = new CountedCollection<CountedCollection<string>>();

0
投票

这是

ToCounter
LINQ 运算符的高性能实现,它采用可枚举序列并返回一个以序列元素作为键的字典。生成的字典的
int
值表示每个元素在
source
序列中出现的次数:

public static Dictionary<TSource, int> ToCounter<TSource>(
    this IEnumerable<TSource> source,
    IEqualityComparer<TSource> comparer = default)
{
    ArgumentNullException.ThrowIfNull(source);

    Dictionary<TSource, int> dictionary = new(comparer);
    foreach (TSource item in source)
        CollectionsMarshal.GetValueRefOrAddDefault(dictionary, item, out _)++;
    return dictionary;
}

CollectionsMarshal.GetValueRefOrAddDefault
是一种高级 API,允许通过对键的单个
GetHashCode
调用来添加或更新字典。
int
类型的默认值为
0
,这使得实现非常简单(无需声明 ref 局部变量)。

© www.soinside.com 2019 - 2024. All rights reserved.