WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   General Authoring Discussion (https://www.wowinterface.com/forums/forumdisplay.php?f=20)
-   -   Getting the number of indexes in an array. (https://www.wowinterface.com/forums/showthread.php?t=48857)

Aanson 01-23-14 05:05 PM

Getting the number of indexes in an array.
 
Has anyone else noticed that since the most recent update, using the select function with the first arg "#" always results in a return value of 1?

Lua Code:
  1. self.Events = {"PLAYER_ENTERING_WORLD", "PLAYER_REGEN_DISABLED", "PLAYER_REGEN_ENABLED"};
  2.  
  3. for i = 1, select("#", self.Events) do
  4.   self:RegisterEvent(self.Events[i]);
  5. end

I've had to change to this instead.

Lua Code:
  1. #self.Events

Resike 01-23-14 05:08 PM

You need to use select as (select("#", self.Events)) but don't get why would you want to use select in that function.

Seerah 01-23-14 05:14 PM

Isn't that what you should be doing anyway?

I mean, this is the documentation I found on using "#" with select, anyway" of wowpedia.
Lua Code:
  1. local num = select('#', ...) -- Returns the number of arguments in the ellipsis.

You have a table there instead of a vararg. The number of arguments there in that case would be one.

I always had an aversion to using select() anyway. I would do that this way:
Lua Code:
  1. local events = {
  2.      "EVENT_ONE",
  3.      "EVENT_TWO",
  4.      "EVENT_THREE"
  5. }
  6.  
  7. for k,v in pairs(events) do
  8.      myFrame:RegisterEvent(v)
  9. end

semlar 01-23-14 05:27 PM

In this particular case I would just call RegisterEvent 3 times because it's shorter, easier to read, and would use less resources.

Otherwise, pairs or ipairs would be better than getting the length of the table to loop over it.

Aanson 01-23-14 05:43 PM

Using "#" to get the number of indices of an array was not limited to varargs. It could be used for any array. It just so happens that a vararg expression is an array.

In the example provided, the event list will change depending on several factors which means that I'm unable to just register 3 events. I would do just that, if that wasn't the case.

I think it to be good practice to avoid using pairs/ipairs wherever possible. Especially when the function isn't just called once during set-up.

Anyone know the better of these two? getn(self.Events) vs #self.Events? I expect it's probably negligible to the point of being irrelevant.

Thanks for your input.

Aanson 01-23-14 05:45 PM

Quote:

Originally Posted by Resike (Post 290056)
You need to use select as (select("#", self.Events)) but don't get why would you want to use select in that function.

?

That's not true.

Torhal 01-23-14 05:52 PM

Quote:

Originally Posted by Aanson (Post 290059)
<snip>

Anyone know the better of these two? getn(self.Events) vs #self.Events? I expect it's probably negligible to the point of being irrelevant.
<snip>

The table.getn method was actually deprecated in Lua 5.1 in favor of the unary length operator (#). You should also be using pairs for dictionary-style tables. For array-style tables, you can use either ipairs or the (slightly faster) incremental loop.

Aanson 01-23-14 06:05 PM

Quote:

Originally Posted by Torhal (Post 290061)
The table.getn method was actually deprecated in Lua 5.1 in favor of the unary length operator (#). You should also be using pairs for dictionary-style tables. For array-style tables, you can use either ipairs or the (slightly faster) incremental loop.

Yeah, I always prefer incremental loops as opposed to ipairs. Cheers :)

Phanx 01-23-14 07:14 PM

Quote:

Originally Posted by Resike (Post 290056)
You need to use select as (select("#", self.Events)) but don't get why would you want to use select in that function.

No. Please, stop posting misinformation. If you are not absolutely sure that what you are posting is valid for Lua programming in the WoW environment, preface it with an "I think" or don't post it at all. :mad:

The only thing wrapping a select call in parentheses does is truncate the list of returns to a single value (the first one returned) but when you're only assigning one variable -- eg. local var = select("#", ...) -- there is absolutely no benefit to or effect from doing that. The only reason to do wrap a select call in parentheses would be to something other than the first returned value, without assigning it to a variable, and in a context where the values passed after the one you wanted would cause problems. For example, if you have the following function:

Code:

function GetSomeNumbers()
    return 1, 2, 3, 4, 5
end

... and you wanted to loop from 1 to 3 using the return value from this function, you can do it two ways:

Code:

local _, _, n = GetSomeNumbers()
for i = 1, n do ...

Code:

for i = 1, (select(3, GetSomeNumbers())) do ...
Here in this highly contrived example, if you used the second (far less efficient) method, and did not add the extra parentheses (highlighted above in orange) around the select call, you would effectively be writing:

Code:

for i = 1, 3, 4, 5 do ...
... which would (a) be passing 4 as the increment value for the loop (so i would be 1, then 5, then 9, and so on) and (b) be passing 5 as a 4th value that for doesn't know what to do with and would trigger an error.

Quote:

Originally Posted by Aanson (Post 290059)
Using "#" to get the number of indices of an array was not limited to varargs. It could be used for any array. It just so happens that a vararg expression is an array.

I think you're confused. In your example:

Code:

local events = { "one", "two", "three }
local num = select("#", events)

... num should be 1, since you are passing only one value -- your table. If you want to get the length of the table, you need to use the # operator, not the special string "#" with select:

Code:

local events = { "one", "two", "three }
local num = #events

That's how it's always worked.

Seerah 01-23-14 07:42 PM

Quote:

Originally Posted by semlar (Post 290058)
In this particular case I would just call RegisterEvent 3 times because it's shorter, easier to read, and would use less resources.

Ah, yes. And this. I honestly didn't scroll to see how many events you had in your table.

Aanson 01-23-14 08:04 PM

Quote:

Originally Posted by Seerah (Post 290069)
Ah, yes. And this. I honestly didn't scroll to see how many events you had in your table.

See my other post in this thread.

Rainrider 01-24-14 04:14 AM

In case it's still unclear:
Code:

for i = 1, select("#", unpack(self.Events)) do
will result in what you seem to have expected from select. Don't do it that way though :)

Vlad 01-24-14 07:14 AM

I'm sorry but this makes me cringe. :(

After I saw 'for i = 1, select("#", unpack(self.Events)) do' I had to write back!

Why not use the standard way of writing a table loop?

Code:

local events = {"A", "B", "C"}
for i = 1, #events do
  self:RegisterEvent(events[i])
end

The select function is great when fetching a specific argument returned from a function that returns a list of arguments, and using "#" returns how many arguments were returned.

Code:

function Events()
  return "A", "B", "C"
end

for k, v in ipairs({Events()}) do
  self:RegisterEvent(v)
end

Also this one works, not ideal but works. You encapsulate the returned arguments in a table and it will return the same table as in the first example. You then iterate it directly using ipairs.

In any case I find this to be a much better approach than unpacking the table to then use select "#" on it to iterate just over the index.

Rainrider 01-24-14 01:16 PM

It seems 3 lines are too much to read, Vlad. What the TE seemed to expect select to return is actually the result of the code snippet I posted. Knowing how unpack works, helps understanding how select works. That was the point of my previous point. Maybe I failed at it, maybe not. I also stated (s)he should not use it like that. So please read before you criticize.

Vlad 01-24-14 05:55 PM

To be honest I couldn't quite tell the purpose at first, so I hastily posted what my first gut feeling told me was the right response - sorry if I made you feel bad in any way! :)

Phanx 01-24-14 06:11 PM

Quote:

Originally Posted by Rainrider (Post 290108)
It seems 3 lines are too much to read, Vlad. What the TE seemed to expect select to return is actually the result of the code snippet I posted. Knowing how unpack works, helps understanding how select works. That was the point of my previous point. Maybe I failed at it, maybe not. I also stated (s)he should not use it like that. So please read before you criticize.

The problem with posting "bad" examples and saying "don't use this" is that -- as you yourself are complaining -- people don't actually read the "don't use this" part, and end up using your cringe-worthy anti-example as real code in their real addon. I make a habit of never posting functional code that should not actually be used, and I strongly recommend you (and everyone else) adopt this habit, too. If you want to show how something works, make up an example that wouldn't make you want to gouge your eyes out if you saw it in a real addon. :p

Rainrider 01-25-14 01:44 PM

If a person comes to a medium for written communication to ask questions, I assume they do read. If they don't, it's all their fault.


All times are GMT -6. The time now is 02:45 AM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI