It looks like you're new here. If you want to get involved, click one of these buttons!
I wrote this function to separate a table into its numerically-indexed and hash-table components:
function separateNumericallyIndexedAndHashTablesIn(thisTable)
local numericalTable, hashTable = {}, {}
for k, v in pairs(thisTable) do
print(k, v)
if type(k) == "number" then
numericalTable[k] = v
else
hashTable[k] = v
end
end
return numericalTable, hashTable
end
And I wrote this code in CodeaUnit to test it (I’m including the print statements I used to debug it);
_:test("separateNumericallyIndexedAndHashTablesIn(...) returns correct tables", function()
--create result flags
local totalResult, numericalCountRight, numericalResult, hashCountRight, hashResult
--make test table and verification tables to check results against
local tableForKey = {}
local testTable = {[1] = "one", [2] = "two", [4] = "four", [10] = "ten",
["red"] = "foo1", ["five"] = "foo2", [tableForKey] = "foo3"}
local correctNumericals = {[1] = "one", [2] = "two", [4] = "four", [10] = "ten"}
local correctHash = {["red"] = "foo1", ["five"] = "foo2", [tableForKey] = "foo3"}
--run the function
local returnedNumericals, returnedHash = separateNumericallyIndexedAndHashTablesIn(testTable)
--inspect counts
local numericalCounter = 0
for i, v in pairs(returnedNumericals) do
numericalCounter = numericalCounter + 1
end
numericalCountRight = numericalCounter == 4
print(table.unpack(correctNumericals))
print(table.unpack(returnedNumericals))
local hashCounter = 0
for i, v in pairs(returnedHash) do
hashCounter = hashCounter + 1
end
hashCountRight = hashCounter == 3
--inspect contents
if numericalCountRight and hashCountRight then
numericalResult = true
hashResult = true
for i, v in pairs(correctNumericals) do
if v ~= returnedNumericals[i] then numericalResult = false end
end
for i, v in pairs(correctHash) do
if v ~= returnedHash[i] then hashResult = false end
end
end
--overall result is AND combination of all results
print(numericalCountRight, numericalResult, hashCountRight, hashResult)
totalResult = numericalCountRight and numericalResult and hashCountRight and hashResult
_:expect(totalResult).is(true)
end)
...does this look right? Are there any cases you think this would miss?
Comments
@UberGoober - I'm sure this will come in handy sometime, thanks for the post. Always looking for any new tools that I can add for debugging (largely because I make a mess of coding!!!)
Just out of interest, started a new project and I thought - 'can I place a few generic tools in a dependency for that project?' - which I can hopefully use on other projects. Tried it out but ended up placing specific tools like parameter.watch(). No big deal - I just have a dependency project for each development project. But it does make it easy to switch them on and off by turning your dependency on and off.
i agree that the code separates numeric from non-numeric keys. i'm not sure if you think it produces an array table and a hashed table, and i very much doubt that it does.
i'm curious ... what purpose have you for this?
I was making a table that had both an array part and a hash part, and I realized the easiest way to test it would be to separate the parts and examine them each on their own.
And then I realized the code to do that could be generalizable, and plus might need testing on its own anyway.
@RonJeffries I think I’ve corrected it so it returns an array table and a hash table.
It now checks for a key being an integer and not just a number.
If I’m wrong, could you suggest a test I could add to make it fail?
New function:
New test:
i think it splits the, but i don't think you're guaranteed an output you could use ipairs on. what if it just had 1 and 39?
@RonJeffries I think the output would be identical to a table made like this:
…and no, I don’t think an ipairs iteration would reach all the numerical indexes in it, but I think that’s nothing to do with my code, it’s just how lua behaves.
I think lua only guarantees array-type behavior up to the first sequential index that returns nil.
So I think lua would treat the tables { 1 = “foo”, 2 = “bar”, 4 = “etsky” } and { 1 = “foo”, 2 = “bar”, 4 = “etsky”, 39 = “zee” } as identical for the purposes of ipairs and the # length operator—because in both of them, checking the value at index 3 would return nil, and it would stop there.
To be explicit, using # to get each table’s length would return 2 for both, and if you used ipairs to concatenate their strings, both would output only “foobar”.
I think table.unpack() also gives unexpected results when there are index gaps, and possibly a few other language features similarly get tripped up by gaps.
But none of those problems are either solved or made worse by this code here, so I don’t think my code is actually doing anything wrong, unless I’m misunderstanding your point—am I?
i think your code does put all numeric keys that evaluate to integers into one table, and the others into the other table. i'm not sure what it does with 10.0 or other integer floats: i suspect it puts them with the integers.
aside from "this is interesting", i don't get it. if we throw a table at it that we have just lying around ... what use are the output tables? i don't see what it's good for.
but i think it probably does what you think it does.
interesting fact: t[1.0] == t[1]. but run this:
@RonJeffries well as I noted, I think, it’s for testing.
I have a table that I’m using both the array parts and the hash parts of, and they reference each other.
To inspect the table, to be sure it’s doing what I think it’s doing, I think it’s going to be much simpler to be able to split it up when I need to, because then I can run
pairs()
on each table individually, and I can be sure I’m inspecting only the part I want to test.this is not advice, but based on my small understanding of what you're doing, i might:
If i find that i have something together and then sometimes want it apart, i treat it as a clue that either it needs to be two things, or one thing with smart behavior, or one of the two things is something i shouldn't do, at least not that way.
@RonJeffries You might be right.
I was partly doing it this way because every table in the array holds one or more elements from the hash, and every hash element points to the table it’s in.
And I was partly doing it this way just because lua can do it, and it’s a unique language feature that seems like it was intended to be used for this sort of thing.
yes, it's fun just to see what we can make it do
@RonJeffries
I expanded your test there a bit to see what was going on. Super weird.
what's going on is that the sum of 100 0.01s is not 1.0. it just rounds to 1,0 for print. if you print x-1, you get 6.6613381477509e-16
this is why even 64bit floats aren't good for money calcs.
it's not a problem with the language, it's an inherent part of binary (floating point) arithmetic. 1/10 decimal is an infinite repeating fraction in binary. just as no finite decimal word size can represent 1/3, 0.33333333..., binary can't do 1/10. it's just a thing, one of many, that programmers need to know.