JeffreySarnoff/NamedTupleTools.jl

random_namedtuple

cscherrer opened this issue · 1 comments

Hi @JeffreySarnoff , I'd like to contribute some of the things I've been working on lately. First up:

"""
    random_namedtuple(width, depth; names='a':'z')

Generate a random nested named tuple. This is useful for tests.

Example:

    julia> randnt(3,3)
    (e = (o = (l = :l, e = :e, s = :s), d = (x = :x, e = :e, a = :a), a = (i = :i, u = :u, d = :d)), 
    f = (b = (y = :y, k = :k, o = :o), a = (b = :b, f = :f, k = :k), z = (j = :j, b = :b, u = :u)), 
    t = (b = (q = :q, k = :k, s = :s), c = (d = :d, u = :u, a = :a), h = (u = :u, c = :c, m = :m)))
"""
function random_namedtuple(width, depth; names='a':'z')
    k = unique(Symbol.(rand(names, width)))
    if depth  1
        return namedtuple(k)(k)
    else
        nts = Tuple((randnt(width, depth-1; names=names) for _ in 1:length(k)))
        return namedtuple(k)(nts)
    end
end 

Any thoughts on this? If you like it, where should it go?

Thank you. Some thoughts:

We should strive to comport with the interface to Random.rand.

To generate symbols that serve as names, we can do something like

const LCASE = collect('a':'z');

function symbol(nchars::Int=1, offset::Int=0)
  nchars = max(1, min(26, nchars))
  ofs  = max(0, min(offset, 26-nchars))
  return Symbol(join(LCASE[1+ofs:nchars+ofs]))
end

symbols(n ,width; randwidth::Bool=false) = 
  randwidth ? [symbol(rand(1:width), i) for i=0:n-1] : [symbol(width, i) for i=0:n-1]

if the values are the same as the names (for simplicity)

function rand(::Type{NamedTuple}, n::Int)
  nchars = (div(n, 26) + 1)
  syms = Tuple(symbols(n, nchars))
  return NamedTuple{syms}(syms)
end

however also using Ints for values should be supported, at minimum

rand(NamedTuple, n; nesting::Int=0, randnest::Bool=false)
should be built on above