lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


To add to the many excellent replies you have already received:

Traversing just the "non-sequence" entries is unfortunately not as simple as traversing the hash part. A sequence may (at least in principle - in practice a rehash would move it to the list part) live entirely in the hash part. A sequence may live partially in the list and partially in the hash part. Or ideally (and probably the case most of the time, when care is taken to produce sequences sequentially), a sequence may live just in the list part. The list part need not contain a proper sequence though; it may have holes.

This means that implementing such a "kpairs" would not be as efficient as traversing the hash part. Instead, you'd first have to use ipairs to find the length of the sequence, and then do a normal pairs traversal, filtering out those keys that are in the sequence.

So really, there is unfortunately pretty much no way around iterating the table twice (in the worst case at least).

Here's my attempt at such a proper "kpairs" implementation:

function kpairs(t)
	local n = 0
	while t[n + 1] do n = n + 1 end
	local function knext(_, k)
		local nk, nv = next(t, k)
		if type(nk) == "number" and math.tointeger(nk) and nk >= 1 and nk <= n then
			return knext(nil, nk)
		end
		return nk, nv
	end
	return knext
end
for k, v in kpairs{1, 2, 3, nil, 4, a = 5, [true] = 6, [3.5] = 1, [0] = 2} do
	print(k, v)
end


(A common misconception is that pairs always iterates a sequence first and inorder. pairs does indeed start traversal in the list part, which is iterated inorder, but as said above, sequences need not live (entirely) in the list part. This is not guaranteed by the reference manual however, and it doesn't always work in practice either; you can construct tables that serve as counterexamples, however rare they may be in practice.)

- Lars

On 22/10/2023 10:52, Hans van der Meer wrote:
This question might have come up earlier, but I have not seen it. Thus I dare to ask.

With ipairs() a table is walked through the array sequence in the table.
With pairs() all elements are visited while traversing the table, the sequence as well as the records.
However, sometimes I need to visit the record keys only, leaving the elements of the sequence out.
Of course I can do:
for k,v in pairs(t) do
if not tonumber(k) then ... end
end

But why isn't there a kpairs() for the record keys? I think it would make some programs easier, especially where the relevant pairs() function is passed to another function.

If I am wrong I will gladly hear it.

yours sincerely
dr. Hans van der Meer