Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IEnumerable<T, int>, Arity and Generic Type Definitions

I have a class Counter that counts things by key. Simplified:

public class Counter<T> {
    private Dictionary<T, int> counts;

    public void Increment(T key) {
        int current;
        bool exists = counts.TryGetValue(key, out current);
        if (exists) {
            counts[key]++;
        } else {
            counts[key] = 1;
        }
    }
}

It does a number of other things specialized to my needs, but that's the essence. So far, it works great.

Now I want to enable it to be used in a Linq query (with both the keys and the values). Do to that, I think I need to implement

IEnumerable<T, int>

So I added:

public class Counter<T> : IEnumerable<KeyValuePair<T, int>> {
    // ...
    IEnumerator<KeyValuePair<T, int>> 
    IEnumerable<KeyValuePair<T, int>>.GetEnumerator()
    {
        return ((IEnumerable<KeyValuePair<T, int>>)counts).GetEnumerator();
    }
    System.Collections.IEnumerator 
    System.Collections.IEnumerable.GetEnumerator()
    {
        return counts.GetEnumerator();
    }

Which unfortunately leads to the compiler error

The number of generic arguments provided doesn't equal the arity of the generic type definition. Parameter name: instantiation

Questions

  1. What the heck is arity?
  2. Am I on the right path to make this type usable from Linq?
  3. How do I fix the implementation?

UPDATE: Typo

I had a typo while simplifying my code to post. The code is in fact attempting to implement IEnumerable<KeyValuePair<T, int>> and not IEnumerable<T, int>

like image 480
Eric J. Avatar asked Jan 14 '23 12:01

Eric J.


1 Answers

  1. Arity is a fancy way of saying "the number of parameters". That's the root of words "binary" (taking two parameters), "unary" (taking one parameter), and "ternary" (taking three parameters).
  2. No, not quite: LINQ is rooted in functional programming, and functional programming hates all state, preferring functions with no side effects. Unfortunately, your counter keeps state: that's the counts dictionary that you modify, which is a side effect.
  3. If you want to count things by key, LINQ already offers you adequate facilities to do so.

Here is how you can get item counts by key:

var counters = keyedData
    .GroupBy(item => item.MyKey)
    .ToDictionary(g => g.Key, g => g.Count());
like image 85
Sergey Kalinichenko Avatar answered Jan 24 '23 11:01

Sergey Kalinichenko