英文:
Iterate over values in an object in Lua (by order)
问题
当我调用 p.main()
时,我希望它打印出 Jan Feb ... Dec
(按顺序),但实际上它打印出的是 Jan Mar Apr Oct Feb Dec Nov Aug Jul May Jun Sep
,对我来说看起来是相当随机的顺序。
提前感谢!
英文:
I am looking for a simple solution for my problem. I've got this code:
local Month = {
Jan = 1, Feb = 2, Mar = 3, Apr = 4,
May = 5, Jun = 6, Jul = 7, Aug = 8,
Sep = 9, Oct = 10, Nov = 11, Dec = 12
}
...
p.main = function()
local text = ""
for k,v in pairs(Month) do
text = text .. " " .. k;
end
return text;
end
When I call p.main()
I would like it to print Jan Feb ... Dec
(in order) though it prints Jan Mar Apr Oct Feb Dec Nov Aug Jul May Jun Sep
which seems to me quite a random order.
Thanks in advance!
答案1
得分: 6
Lua表中的哈希部分是无序的。字符串键存储在哈希部分。这就是为什么您观察到"随机"顺序的原因。
只需将您的Month
表从月份名称到数字的映射转换为数字到名称的映射,即反转它并将其转换为列表:
local monthnames = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}
然后,您可以使用ipairs
(而不是pairs
)方便地按顺序迭代它 - 更重要的是,您的p.main
函数简化为对table.concat
的单个调用,这是Lua的内置函数,用于连接字符串列表,并且由于该值是常量,您可以预先计算它:
local space_separated_monthnames = table.concat(monthnames, " ")
function p.main()
return space_separated_monthnames
end
这不会添加前导空格,但我认为这并不是您的意图。
如果您需要保留旧的查找,也没问题 - 您可以从列表生成它:
local monthnumber = {}
for i, name in ipairs(monthnames) do
monthnumber[name] = i
end
还要注意,在循环中进行字符串连接是Lua中的一个反模式,因为它既低效(二次 vs. 线性,如果您至少构建较长的字符串,这会非常明显),又不方便编写(例如,您的代码生成一个可能不需要的前导空格,而且需要更多的代码来避免它)。一般来说,如果您看到类似以下的东西:
local str = vals[1]
for i = 2, #vals do
str = str .. separator .. vals[i]
end
请对其进行重构:
local str = table.concat(vals, separator)
这既有助于性能又有助于可读性。
英文:
The hash part of tables in Lua is unordered. String keys go in the hash part. This is why you're observing the "random" order.
Simply convert your Month
table from a mapping from month names to numbers to a mapping from numbers to names, i.e. flip it and convert it to a list:
local monthnames = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}
then you can conveniently iterate it in order using ipairs
(rather than pairs
) - even more, your p.main
function simplifies to a single call to table.concat
, a Lua built-in function for concatenating a list of strings, and since the value is constant, you can pre-calculate it:
local space_separated_monthnames = table.concat(monthnames, " ")
function p.main()
return space_separated_monthnames
end
This won't add a leading space, but I don't think that's intended anyways.
If you need to keep the old lookup, no problem - you can generate it from the list:
local monthnumber = {}
for i, name in ipairs(monthnames) do
monthnumber[name] = i
end
Also note that string concatenation in a loop is an antipattern in Lua since it is both inefficient (quadratic vs. linear, very noticeable if you're building longer strings at least) and inconvenient to write (e.g. your code emits a probably unwanted leading space and more code would be required to not emit it). In general, if you see something like:
local str = vals[1]
for i = 2, #vals do
str = str .. separator .. vals[i]
end
refactor it to
local str = table.concat(vals, separator)
both for performance and readability.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论