Can I get the last value from an iterator? - lua

I would like to split a string by a separator and get only the last part. I
don't care about the rest. I know I can do:
local last
for p in string.gmatch('file_name_test', '_%w+$') do last = p end
Which works, but is, IMHO, ugly.
Is there a more elegant way to say:
local last = string.gmatch('file_name_test', '_%w+$')[1]
Which doesn't work because gmatch returns an iterator (and not a table).

Use string.match which is not an iterator:
local last = string.match('file_name_test', '_(%w+)$')
print (last) --> test

Although the other answers do give you a correct answer for your situation, I am going to propose an answer to your question. Which was to get the first item from an iterator.
And the answer is actually quite simple. Since an iterator is just something that continues to return until it returns nil, we just have to call it!
local first = string.gmatch('file_name_test', '_%w+$')()
I am quite confused however, because in your question you also ask about the last thing it will return. I'm sad to say you cannot do this without iterating over them all, because an iterator cannot "jump ahead".

The pattern _%w+$ will only ever return a single match. That's because you anchored it at the end of the string, so it can only either match or fail to match (if there isn't an underscore followed by at least one %w character at the end).
The g* series of pattern matching are for iterating over a sequence of matches. If you want all the matches all at once (returned as multiple return values), use the non-g-prefixed functions. Like string.match:
string.match('file_name_test', '_%w+$')
If there is no match, then you'll get nil back.

Related

Directly return a table entry from a (simplest) function in Lua

I wanted to write the simplest possible function which let me return the desired value in a nameless table and, ideally, it should be something like this:
function RL_MyTool:Version(n)
return {"0.4.0", "20221003-0230", "13.5.5"}[n]
end
But, of course, that's not allowed in Lua...
So, off the top of my head, I can think on these two other possibilities:
1:
function RL_MyTool:Version(n)
local t = {"20221003-0230", "13.5.5"}
return t[n] or "0.4.0"
end
2:
function RL_MyTool:Version(n)
local n, t = n or 1, {"0.4.0", "20221003-0230", "13.5.5"}
return t[n]
end
Both of them slightly different from each other but doing the same, counting with the advantage of returning a default value if no argument is given, which is good. BUT... Do you think I could still have a possibility of writing it like in the very simplest fashion way above? Basically, what I'd like is not even have to use a single variable or table declaration along the function but still let me return the specified table entry when called.
Well, that's all. Of course if it's finally not possible (as I'm afraid) it won't be the end of the world 🙄, but I wanted to be sure I wasn't missing any Lua trick or something that let me do it more like I firstly imagined... Thanks!
P.S. Oh, I don't see how, but of course if it could be achieved without the necessity of even using a table at all, that would be equally valid or even better.
EDIT: BTW, for the record and based in #Piglet (great!) answer, I got to reduce it even more this way:
function RL_MyTool:Version(n)
return ({"0.4.0", "20221003-0230", "13.5.5"})[n or 1]
end
Improving code usability/maintenance a bit at the same time by avoiding duplicated values... Kind of a win-win-win 😁
Just put the table in parenthesis.
function RL_MyTool:Version(n)
return ({"0.4.0", "20221003-0230", "13.5.5"})[n] or "0.4.0"
end
But what is the purpose of this? Code should be easy to read and easy to work on. There is absolutely no reason to not use a local table. You don't have to pay a dollar for each line of code.

Lua: Sort table of numbers with multiple dots

I have a table of strings like this:
{
"1",
"1.5",
"3.13",
"1.2.5.7",
"2.5",
"1.3.5",
"2.2.5.7.10",
"1.17",
"1.10.5",
"2.3.14.9",
"3.5.21.9.3",
"4"
}
And would like to sort that like this:
{
"1",
"1.2.5.7",
"1.3.5",
"1.5",
"1.10.5",
"1.17",
"2.2.5.7.10",
"2.3.14.9",
"2.5",
"3.5.21.9.3",
"3.13",
"4"
}
How do I sort this in Lua? I know that table.sort() will be used, I just don't know the function (second parameter) to use for comparison.
Given your requirements, you probably want something like natural sort order. I described several possible solution as well as their impact on the results in a blog post.
The simplest solution may look like this (below), but there are 5 different solutions listed with different complexity and the results:
function alphanumsort(o)
local function padnum(d) return ("%03d%s"):format(#d, d) end
table.sort(o, function(a,b)
return tostring(a):gsub("%d+",padnum) < tostring(b):gsub("%d+",padnum) end)
return o
end
table.sort sorts ascending by default. You don't have to provide a second parameter then. As you're sorting strings Lua will compare the strings character by character. Hence you must implement a sorting function that tells Lua which comes first.
I just don't know the function (second parameter) to use for
comparison.
That's why people wrote the Lua Reference Manual
table.sort (list [, comp])
Sorts the list elements in a given order, in-place, from list1 to
list[#list]. If comp is given, then it must be a function that
receives two list elements and returns true when the first element
must come before the second in the final order, so that, after the
sort, i <= j implies not comp(list[j],list[i]). If comp is not given,
then the standard Lua operator < is used instead.
The comp function must define a consistent order; more formally, the
function must define a strict weak order. (A weak order is similar to
a total order, but it can equate different elements for comparison
purposes.)
The sort algorithm is not stable: Different elements considered equal
by the given order may have their relative positions changed by the
sort.
Think about how you would do it with pen an paper. You would compare each number segment. As soon as a segment is smaller than the other you know this number comes first.
So a solution would probably require you to get those segments for the strings, convert them to numbers so you can compare their values...

Array Formula not counting correctly

I have one array formula which is behaving differently to all of my others.
https://docs.google.com/spreadsheets/d/150rfbeuUW9RuG-iX6EGZAP83iOGr0KG_pn1ts-SXKoU/edit?usp=sharing
I just can't get 'Country Rating'!H2 to return the results I want and for some reason isn't counting the data in D:D correctly. 'Country Rating'!J2 is almost identical and seems to be working fine. I've narrowed it down to being an issue relating to the last "-" in the H2 formula but can't get any further.
I'm sure this is a very basic thing that I'm missing but it's driving me mad!
You need to use those regex matches '.*Vegetarian.*' and matches '.*Vegan.*' as matches returns true only in case of a full match.
Also .*Vegan* was missing . before the last *, meaning zero or more n chars at the end.
And be aware that regex in matches is case sensitive and flags do not work there: you cannot use this (?i).*vegan.* for example.

We giving a task for Lua table but it is not working as expectable

Our task is create a table, and read values to the table using a loop. Print the values after the process is complete. - Create a table. - Read the number of values to be read to the table. - Read the values to the table using a loop. - Print the values in the table using another loop. for this we had written code as
local table = {}
for value in ipairs(table) do
io.read()
end
for value in ipairs(table) do
print(value)
end
not sure where we went wrong please help us. Our exception is
Input (stdin)
3
11
22
abc
Your Output (stdout)
~ no output ~
Expected Output
11
22
abc
Correct Code is
local table1 = {}
local x = io.read()
for line in io.lines() do
table.insert(table1, line)
end
for K, value in ipairs(table1) do
print(value)
end
Let's walk through this step-by-step.
Create a table.
Though the syntax is correct, table is a reserved pre-defined global name in Lua, and thus cannot should not be declared a variable name to avoid future issues. Instead, you'll need to want to use a different name. If you're insistent on using the word table, you'll have to distinguish it from the function global table. The easiest way to do this is change it to Table, as Lua is a case-sensitive language. Therefore, your table creation should look something like:
local Table = {}
Read values to the table using a loop.
Though Table is now established as a table, your for loop is only iterating through an empty table. It seems your goal is to iterate through the io.read() instead. But io.read() is probably not what you want here, though you can utilize a repeat loop if you wish to use io.read() via table.insert. However, repeat requires a condition that must be met for it to terminate, such as the length of the table reaching a certain amount (in your example, it would be until (#Table == 4)). Since this is a task you are given, I will not provide an example, but allow you to research this method and use it to your advantage.
Print the values after the process is complete.
You are on the right track with your printing loop. However, it must be noted that iterating through a table always returns two results, an index and a value. In your code, you would only return the index number, so your output would simply return:
1
2
3
4
If you are wanting the actual values, you'll need a placeholder for the index. Oftentimes, the placeholder for an unneeded variable in Lua is the underscore (_). Modify your for loop to account for the index, and you should be set.
Try modifying your code with the suggestions I've given and see if you can figure out how to achieve your end result.
Edited:
Thanks, Piglet, for corrections on the insight! I'd forgotten table itself wasn't a function, and wasn't reserved, but still bad form to use it as a variable name whether local or global. At least, it's how I was taught, but your comment is correct!

How do I remove the first occurence of a substring in string?

How can I remove the first occurence of a given substring?
I have:
phrase = "foobarfoo"
and, when I call:
phrase.some_method_i_dont_know_yet ("foo")
I want the phrase to look like barfoo.
I tried with delete and slice but the first removes all the occurrences but the second just returns the slice.
Use sub! to substitute what you are trying to find with ""(nothing), thereby deleting it:
phrase.sub!("foo", "")
The !(bang) at the end makes it permanent. sub is different then gsub in that sub just substitutes the first instance of the string that you are trying to find whereas gsub finds all instances.
sub will do what you want. gsub is the global version that you're probably already familiar with.
Use the String#[] method:
phrase["foo"] = ""
For comparison, in my system this solution is 17% faster than String#sub!

Resources