using System; using System.Collections.Generic; using System.Linq; namespace JiebaNet.Segmenter.Common { public interface ICounter { int Count { get; } int Total { get; } int this[T key] { get; set; } IEnumerable> Elements { get; } /// /// Lists the n most common elements from the most common to the least. /// /// Number of elements, list all elements if n is less than 0. /// IEnumerable> MostCommon(int n = -1); /// /// Subtracts items from a counter. /// /// void Subtract(IEnumerable items); /// /// Subtracts counts from another counter. /// /// void Subtract(ICounter other); /// /// Adds items to a counter. /// /// void Add(IEnumerable items); /// /// Adds another counter. /// /// void Add(ICounter other); /// /// Union is the maximum of value in either of the input . /// /// The other counter. ICounter Union(ICounter other); void Remove(T key); void Clear(); bool Contains(T key); } public class Counter: ICounter { private Dictionary data = new Dictionary(); public Counter() {} public Counter(IEnumerable items) { CountItems(items); } public int Count => data.Count; public int Total => data.Values.Sum(); public IEnumerable> Elements => data; public int this[T key] { get => data.ContainsKey(key) ? data[key] : 0; set => data[key] = value; } public IEnumerable> MostCommon(int n = -1) { var pairs = data.Where(pair => pair.Value > 0).OrderByDescending(pair => pair.Value); return n < 0 ? pairs : pairs.Take(n); } public void Subtract(IEnumerable items) { SubtractItems(items); } public void Subtract(ICounter other) { SubtractPairs(other.Elements); } public void Add(IEnumerable items) { CountItems(items); } public void Add(ICounter other) { CountPairs(other.Elements); } public ICounter Union(ICounter other) { var result = new Counter(); foreach (var pair in data) { var count = pair.Value; var otherCount = other[pair.Key]; var newCount = count < otherCount ? otherCount : count; result[pair.Key] = newCount; } foreach (var pair in other.Elements) { if (!Contains(pair.Key)) { result[pair.Key] = pair.Value; } } return result; } public void Remove(T key) { if (data.ContainsKey(key)) { data.Remove(key); } } public void Clear() { data.Clear(); } public bool Contains(T key) { return data.ContainsKey(key); } #region Private Methods private void CountItems(IEnumerable items) { foreach (var item in items) { data[item] = data.GetDefault(item, 0) + 1; } } private void CountPairs(IEnumerable> pairs) { foreach (var pair in pairs) { this[pair.Key] += pair.Value; } } private void SubtractItems(IEnumerable items) { foreach (var item in items) { data[item] = data.GetDefault(item, 0) - 1; } } private void SubtractPairs(IEnumerable> pairs) { foreach (var pair in pairs) { this[pair.Key] -= pair.Value; } } #endregion } }