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