Quote: "I have dark data (though never worked with it)... would that be any good?"
In most gaming situations the arrays will be much faster than Dark Data; I speed tested the plugin a few years ago. The only instance where Dark Data will be faster is if you run text based queries; say a keyword search of say 10,000 or 20,000 database entries in which case its indexing will kick in. But arguably you would use an SQL database or some .Net Linq query based database for such a thing.
So if you want to use Dark Data, you could use it to store your world; but again it is not good for iteration.
Think your database as a lorry, your array as a car, and raw memory as a motorbike; the motorbike gets to places more quickly than the lorry, the lorry can carry more things than the motorbike. You could carry lots of things on lots of motorbikes; but then it gets tedious.
The car; the array is the best of both worlds, but only when you do not need the organized nature of databases or the speed of raw memory.
I think you should stick with arrays whilst practicing raw memory manipulation. Use raw memory to store lists in arrays; where the array stores a memory address with stores a series of data; or perhaps a series of lists of data. The beauty of raw memory lists in arrays is that list items do not increase the dimension or size of the array.
Arguably a block of 100 voxels could be stored in a list, which inturn is stored in one array entry, so if you need to update these voxels, updating them is as easy as referencing the single array entry and iterating its content.
One other consideration is my
coroutine class tutorial; something which allows you to allocate stacks of memory exclusive for instances of variables, arrays and functions. In a nutshell; the process of running programs in programs; sub-programs; so voxel groups can run side by side using the same functionality with different data.