As far as I can see from the docs, it's just a regular table where values are of type int. It doesn't actually count things for you, rather you have to increase the counter yourself. If you create a CountTable from an iterable, it doesn't count how many times each key is included in it, just assigns 1 as the default value.
I thought it was supposed to be similar to Python's collections.Counter, which actually does indicate the count of each value in the input iterable.
Am I missing something?
I can't see any proc to create a CountTable from any iterable so I think you're wrong with assigning ones, it seems it's defined only for openArray`s. Also, it's not just like any table, as it provides `inc proc. Please notice this method works even if the table does NOT contain the key yet (I agree, it should be mentioned explicitly in the docs)!
import tables
var table = initCountTable[string]()
table.inc("nice")
echo table
It's actually quite unusual for Nim to do anything "for any iterable", even sequtils is SEQqutils, not ITERutils (which is available by nimble, by the way). The most natural approach, for both CountTable and any other nimmish container is probably:
import tables
let iterable = @[3,1,4,1,5,9,2,6,5,3,5,8,9,7,9,3]
var table = initCountTable[int]()
for elem in iterable:
table.inc(elem)
echo table
I can't see any proc to create a CountTable from any iterable so I think you're wrong with assigning ones
toCountTable does that.
Also, it's not just like any table, as it provides inc proc
Well, yes, but you actually have to do the increments manually. That's what bothers me. I wish there was count proc that would do the actual counting:
import tables
proc count[T](keys: openArray[T]): CountTable[T] =
result = initCountTable[T](rightSize(keys.len))
for key in keys: result.inc key
let
mySeq = @[1, 2, 1, 3, 1, 4]
myCounter = mySeq.count()
echo myCounter
It's actually quite unusual for Nim to do anything "for any iterable", even sequtils is SEQqutils, not ITERutils (which is available by nimble, by the way)
Sorry, I think I'm just using the Python terminology here. I. e. iterable is anything you can iterate over: seq, array, openArray, etc.
No, you're wrong. Iterable is ANY container that can be iterated over (including lists, sets etc) while openArray is anything that has an array-like memory layout, i.e. array or seq. Your code fails for containers which with non-linear memory layout:
import lists
proc toList[T](arr: openArray[T]): SinglyLinkedList[T] =
result = initSinglyLinkedList[T]()
for idx in 1 .. arr.len:
result.prepend(arr[^idx])
var li = toList([3,1,4,1,5])
echo li
proc count[T](keys: openArray[T]): CountTable[T] =
result = initCountTable[T](rightSize(keys.len))
for key in keys: result.inc key
let myCounter = li.count() # error here
echo myCounter
What you really meant is:
import lists
type Iterable[T] = concept c
for el in c:
el is T
proc toList[T](arr: openArray[T]): SinglyLinkedList[T] =
result = initSinglyLinkedList[T]()
for idx in 1 .. arr.len:
result.prepend(arr[^idx])
var li = toList([3,1,4,1,5])
echo li
proc count(keys: Iterable): CountTable[keys.T] =
result = initCountTable[keys.T]()
for key in keys: result.inc key
let myCounter = li.count()
echo myCounter
Which fails for my Nim version but should work in the future. As for now, you can use some tricks, like:
import lists
proc toList[T](arr: openArray[T]): SinglyLinkedList[T] =
result = initSinglyLinkedList[T]()
for idx in 1 .. arr.len:
result.prepend(arr[^idx])
var li = toList([3,1,4,1,5])
echo li
# Here we require the keys' type to actually have an associated type
# which is precisely called T (which doesn't have to be true, actually...)
proc count(keys: auto): CountTable[keys.T] =
result = initCountTable[keys.T]()
for key in keys: result.inc key
let myCounter = li.count()
echo myCounter