Suppose that I have a table:
0.8
0.7
0.9
0.5
And I want to get the index of 2 largest values, so in this case, it should return:
3 1
I am quite newbie with Lua, so any help is more than welcome.
Thanks a lot,
You can loop over a table using for loop (for i = 1, #tbl or for i, val in ipairs(tbl)) and keep track of the largest and second to large elements (you'll need to store first index and first value and second index with second value to check the value and save the index). After the loop is done, you get the indexes of the first and second largest elements. Keep in mind that when the first value is updated its old value may need to be checked against the second value.
Another option is to build an array of indexes and sort it based on the values (as the sort can take an optional comparator function):
local function indexsort(tbl)
local idx = {}
for i = 1, #tbl do idx[i] = i end -- build a table of indexes
-- sort the indexes, but use the values as the sorting criteria
table.sort(idx, function(a, b) return tbl[a] > tbl[b] end)
-- return the sorted indexes
return (table.unpack or unpack)(idx)
end
local tbl = {0.8, 0.7, 0.9, 0.5}
print(indexsort(tbl))
This prints 3 1 2 4. If you only need the first two indexes, you can do local first, second = indexsort(tbl). Note that indexsort returns all indexes, so if you only need the first two (and your table is large), you may want to update the function to only return the first two items instead of the entire table.
Related
Im new to lua and have a problem which i believe has an elegant solution, but i just cant make it work. I've read similar questions and answers here on stack overflow and elsewhere for hours as well as testing in online lua compiler but no real progress.
Q:
i start out with an empty table:
local vertices = {}
Now, with a for loop or similar i want to populate this table so the end result has this form:
local vertices = {
{x=-6.0, y=0.0},
{x=0.0, y=1},
}
Where the values in the entries {x=-6.0, y=0.0} are arbitrary, and the number of these {x=0.0, y=1} (coordinates) are also arbitrary.
These values are to be fetched from another table and som calculated in the for loop, but that is the next step. For now i just need help populate my empty table with x,y values in a loop.
Thanks to you all.
You can add elements to a Lua table through
the table constructor local t = { v1, v2, v3 }
assignment t[k1] = v1 t[k2] = v2
table.insert(t, 1) (for consecutive integer indices starting at 1)
rawset(t, 1, 1) if you want to avoid invoking metamethods
table.move to copy elements fro one to another table
...
For your case you can simply use assignment in a for loop.
local vertices = {}
for i = 1, 100 do
vertices[i] = NewVertex();
end
To add 100 vertices to the table.
if a table of N integer is present how to check if an element is repeating if present it shows message that table has repeating elements, if this is to be achieved in minimum time complexity
Hash table is the way to go (ie normal Lua table). Just loop over each integer and place it into the table as the key but first check if the key already exists. If it does then you have a repeat value. So something like:
values = { 1, 2, 3, 4, 5, 1 } -- input values
local htab = {}
for _, v in ipairs(values) do
if htab[v] then print('duplicate value: ' .. v)
else htab[v] = true end
end
With small integer values the table will use an array so will be O(1) to access. With larger and therefore sparser values the values will be in the hash table part of the table which can just be assumed to be O(1) as well. And since you have N values to insert this is O(N).
Getting faster than O(N) should not be possible since you have to visit each value in the list at least once.
I have a table in Lua with, for example:
Array = {5,3,5}
And I want, if possible, a function that returns the position of the highest values.
Probably an easy question but I cannot find the solution...
math.max returns the maximum value. To get the index:
local t = {5,3,5}
local max = math.max(table.unpack(t))
for i, v in ipairs(t) do
if v == max then
print(i)
end
end
Note that the table is passed twice here. If the table is huge, pass the table once and store the highest value and compare manually.
I got two tables, for example:
table1 = { element1, element2, element3, element4 }
table2 = { element1, element3 }
Table 2 refers to some elements of table1, but I don't know which exactly, nor I know their index.
Now, for an specific element I want to check if table2 does contains it or not and insert/remove it in the case.
First thing that jumped to my mind was:
table.remove/insert(table2, table1.elementX)
But due insert/remove does its lookup by index, this doesn't work.
Sure, I could iterate through the whole table until I find the element and remove it, respectively until Iteration is done without match and insert it.
But is there a more performant method to do this?
I do not want to fill table2 with empty fields for bringing the elements on matching indices.
To insert, it's quite straightforward:
table.insert(table1, table2[index])
Unfortunately, to remove, it's a bit more tricky:
local ids = {} -- table containing ids to remove
for i,v in ipair(table1) do
if v == table2[index] then
table.insert(ids, 1, i) -- "1" preprends the value
end
-- At this point, "ids" contains all the ids to remove in the reverse order
for k,v in pair(ids) do
table.remove(table1, v)
end
What happens here is:
An intermediate table is created, it only contains the ids of the table to remove, descending. For example: { 6, 3, 1} (if the value is present 3 times).
That intermediate table is used to update the main table, as you can't use the ids from a table you are updating in a loop (that's what the comments about "transversal" mean).
Note that those operations must be made from the end of the table, because removing an element will change the ids of the following ones.
First revert table2 with
table2reverse = {}
for k,v in pairs(table2) do table2reverse[v]=k end
Then do this:
for k,v in pairs(table1)do
if table2reverse[v] then
table1[k]=nil
end
Finally compact table1.
for k,v in pairs(table1)do
if v == table2[index] then
table.remove/insert(table1, k)
break
end
Of course this works, but I still hope there's a more performante solution.
Due in case of multiple 1000 entrys in table1 and multiple 100 entrys in table2, this is will lead to high cpu usage, wich I want to avoid. (programming a controller with only 200mhz)
I want to delete all entries from a table, wich equals a given value.
Now, I got a pretty little problem one might to know, how to handle.
This is the Code:
function(list_to_search_in, compared_value, invert)
for k,v in pairs(list_to_search_in) do
if invert and v ~= compared_value then
table.remove(list_to_search_in, v)
if not invert and v == compared_value then
table.remove(list_to_search_in, v)
end
end
end
The Problem:
Let's say the table is { 1, 2, 3, 2 }. So when I'm iterating through that loop and come to the first match, it's removed from the table. This means the value and the key is deleted.
Now the key of the deleten value is assigned to the next value in line. But due the skript will check the value of the next key, this value (whichs kay has been just altered) will never be checked.
I thought, a simple
k = k - 1
after a remove would do the job, but it doesn't.
v = nil
would do great I think, but only if garbage-collector does not do his job in this very moment the pairs iterates to the next value.
Anyone has an idea? I would prefer an text-based hint to a finished syntax which solves the problem.
Don't use table.remove for this. It squeezes the "hole" out of array-like tables. That's not allowed during an iteration using pairs/next. Just set the value to nil.
If you need to squeeze holes out of the table then you can either create a new table and populate it with only the values you want to keep or do the removals during the first pass and then squeeze out holes in a second pass.
Also the order of item traversal when using pairs is not guaranteed in any way.