What techniques that everyone should know?

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Wojak
Party member
Posts: 134
Joined: Tue Jan 24, 2012 7:15 pm

Re: What techniques that everyone should know?

Post by Wojak »

This is an implementation without #:

Code: Select all

function isArray(tab)
    local countT = 0
    local countA = 0
    local i = 1
    for k,_ in pairs(tab) do
    	countT = countT + 1
    	if tab[i] then
        	countA = countA + 1
        end
    	if countT ~= countA then
        	return false
        end
        i = i + 1
    end
    return true
end
And this is a duel between # and no#:

Code: Select all

t = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
t2 = {5,4,8,w=5,6,4,8}

function isArray(tab)
    local countT = 0
    local countA = 0
    local i = 1
    for k,_ in pairs(tab) do
    	countT = countT + 1
    	if tab[i] then
        	countA = countA + 1
        end
    	if countT ~= countA then
        	return false
        end
        i = i + 1
    end
    return true
end
local function is_array(t)
      local count = 0
      for k, _ in pairs(t) do
        if type(k) ~= 'number' or k < 1 or math.floor(k) ~= k then return false end
        count = count + 1
      end
      return count == #t
end
print(isArray(t)) --true
print(is_array(t)) --true
print(isArray(t2)) --flase
print(is_array(t2)) --false
t[2] = nil
print(#t) --20
print(isArray(t)) --false
print(is_array(t)) --false
t[20]=nil
t[18]=nil
print(#t) --17?
print(isArray(t)) --false
print(is_array(t)) --true
no# should always treat arrays with embedded nil as not arrays while # can change it's mind...
(tested with lua 5.1, 5.2 JIT 2.0.0,2.0.1,2.0.2 – same thing)
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: What techniques that everyone should know?

Post by kikito »

Well, that confirms my initial suspicions. # can't be trusted :)

Your implementation is interesting, but note that it will return false on some arrays (those with false in their values):

Code: Select all

print(isArray({1,2,false,4})) -- false, but should be true
Also, it uses too many variables - 'i', 'countT' and 'countA' work almost the same way. Here's an implementation that uses the same principle (increasing an integer to check each key), with less variables, and with the false values bug fixed:

Code: Select all

function isArray(t)
    local i = 0
    for _ in pairs(t) do
       i = i + 1
       if t[i] == nil then return false end
    end
    return true
end
I like this one a lot. It is efficient and clean. It needs a bit more testing, but I think it might be better than my original implementation.

Code: Select all

print(isArray({1,2,false,4})) -- true, false-values now work
print(isArray({5,4,8,w=5,6,4,8})) --false, hash keys make it fail

t = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}

print(isArray(t)) --true
t[2] = nil
print(#t) --20
print(isArray(t)) --false
t[20]=nil
t[18]=nil
print(#t) --17
print(isArray(t)) --false
Last edited by kikito on Wed Feb 26, 2014 10:12 am, edited 1 time in total.
When I write def I mean function.
Wojak
Party member
Posts: 134
Joined: Tue Jan 24, 2012 7:15 pm

Re: What techniques that everyone should know?

Post by Wojak »

kikito wrote: Also, it uses too many variables - 'i', 'countT' and 'countA' work almost the same way. Here's an implementation that uses the same principle that you're using (increasing an integer to check each key), with less variables, and with the false values bug fixed:

Code: Select all

function isArray(t)
    local i = 0
    for _ in pairs(t) do
       i = i + 1
       if t[i] == nil then return false end
    end
    return true
end
Great job!
I had a strange feeling that I've missed something...
User avatar
Roland_Yonaba
Inner party member
Posts: 1563
Joined: Tue Jun 21, 2011 6:08 pm
Location: Ouagadougou (Burkina Faso)
Contact:

Re: What techniques that everyone should know?

Post by Roland_Yonaba »

kikito wrote:

Code: Select all

function isArray(t)
    local i = 0
    for _ in pairs(t) do
       i = i + 1
       if t[i] == nil then return false end
    end
    return true
end
Wojak and Kikito, this is brilliant.
The t incremental check trick is soooo clean.
God, I love this forum.

One question, though. According to the Lua documentation, pairs would traverse a table in an unpredictable manner. This is true for dict-tables. But is it guaranteed that, no matter what the Lua implementation is, pairs will just behave like ipairs when given a Lua array ?
Wojak
Party member
Posts: 134
Joined: Tue Jan 24, 2012 7:15 pm

Re: What techniques that everyone should know?

Post by Wojak »

Roland_Yonaba wrote: One question, though. According to the Lua documentation, pairs would traverse a table in an unpredictable manner. This is true for dict-tables. But is it guaranteed that, no matter what the Lua implementation is, pairs will just behave like ipairs when given a Lua array ?
Even if there is no guarantee, it simply don't matter wit this implementation ;)

edit:

Code: Select all

t={[10]=10,[9]=9,[8]=8,[7]=7,[6]=6,[5]=5,[4]=4,[3]=3,[2]=2,[1]=1}
for i,k in pairs(t) do -- not in order
    print(k)
end
print(t[5])
for i,k in ipairs(t)do --in order
    print(k)
end
User avatar
Inny
Party member
Posts: 652
Joined: Fri Jan 30, 2009 3:41 am
Location: New York

Re: What techniques that everyone should know?

Post by Inny »

kikito wrote:

Code: Select all

function isArray(t)
    local i = 0
    for _ in pairs(t) do
       i = i + 1
       if t[i] == nil then return false end
    end
    return true
end
This is really clever, I like it, with the exception that something that is array-like wouldn't fit in here. That is to say, if you keep 'n' as the length of the array as a member of the table, then isArray is false. Maybe I'm not understanding our semantics, are we trying to discover nils embedded in the table's integer indexes as a means to disqualify it, or as a way to detect when the underlying struct no longer takes advantage of the array optimization?
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: What techniques that everyone should know?

Post by kikito »

This is really clever, I like it, with the exception that something that is array-like wouldn't fit in here. That is to say, if you keep 'n' as the length of the array as a member of the table, then isArray is false.
As far as I know, table.getn and table.setn were deprecated in Lua 5.1 and removed in 5.2, as well as using a key called 'n' to handle the length. The "standard" definition of array does not include any non-array values any more (except for backwards-compatibility with Lua 5.0 libraries), so I don't think this is an issue.
Maybe I'm not understanding our semantics, are we trying to discover nils embedded in the table's integer indexes as a means to disqualify it, or as a way to detect when the underlying struct no longer takes advantage of the array optimization?
Both.
When I write def I mean function.
User avatar
slime
Solid Snayke
Posts: 3159
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: What techniques that everyone should know?

Post by slime »

The # operator, ipairs, table.insert, and table.remove all will not work as expected on any "array with holes" in Lua (including, for example, {1, 2, nil, 3}). Either don't use "arrays with holes" at all, or don't use the previously mentioned functions/operators with them.
Lua 5.1 Reference Manual wrote:If the array has "holes" (that is, nil values between other non-nil values), then #t can be any of the indices that directly precedes a nil value (that is, it may consider any such nil value as the end of the array).
User avatar
master both
Party member
Posts: 262
Joined: Tue Nov 08, 2011 12:39 am
Location: Chile

Re: What techniques that everyone should know?

Post by master both »

Since I use the # operator a lot, I write this function to remove "holes" from an array. I'll just leave it here if someone wants to use it.

Code: Select all

 
function removeholes(t)
	local n = 0
	local lasti = 0
	for i,v in pairs(t) do
		if i > lasti then
			lasti = i
		end
	end
	for i = 1, lasti do
		if t[i] == nil then
			n = n + 1
		end
	end
	for y = 1, n do
		for i = 1, lasti do
			if t[i] == nil then
				t[i] = t[i + 1]
				t[i + 1] = nil
			end	
		end
	end
end
 
User avatar
Nixola
Inner party member
Posts: 1949
Joined: Tue Dec 06, 2011 7:11 pm
Location: Italy

Re: What techniques that everyone should know?

Post by Nixola »

If I get it correctly, you can just use table.maxn instead of the first loop:

Code: Select all

     
    function removeholes(t)
       local n = 0
       local lasti = table.maxn(t)
       for i = 1, lasti do
          if t[i] == nil then
             n = n + 1
          end
       end
       for y = 1, n do
          for i = 1, lasti do
             if t[i] == nil then
                t[i] = t[i + 1]
                t[i + 1] = nil
             end   
          end
       end
    end
     
lf = love.filesystem
ls = love.sound
la = love.audio
lp = love.physics
lt = love.thread
li = love.image
lg = love.graphics
Post Reply

Who is online

Users browsing this forum: No registered users and 0 guests