1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
local format = require "format"
local stats = {}
local mt = {__index=stats}
local function new (name_or_obj, parent)
if type(name_or_obj) == "string" then
name_or_obj = {
name = name_or_obj,
parent = parent,
letters = 0,
length = 0,
counts = {},
children = {},
}
end
return setmetatable(name_or_obj, mt)
end
function stats:add (value)
local current = self.counts[value] or 0
if current == 0 then
self.letters = self.letters + 1
end
self.length = self.length + 1
self.counts[value] = current + 1
if self.parent then
self.parent:add(value)
end
end
function stats:sub (name)
local child = new(name, self)
table.insert(self.children, child)
return child
end
function stats:ioc (letters)
letters = letters or self.letters
local subtotal = 0
for _, count in pairs(self.counts) do
subtotal = subtotal + count * (count - 1)
end
return subtotal / (self.length * (self.length - 1) / letters)
end
function stats:dump ()
local function dump (stat)
local letters = (stat.parent or {}).letters
io.write(stat.name, "\t", stat.length, "\t", stat.letters, "\t", format.float(stat:ioc(letters)))
if letters then
io.write("\t", format.float(stat:ioc()))
end
print()
end
dump(self)
for _, child in ipairs(self.children) do
dump(child)
end
end
return new
|