Before you mark this question as duplicate of this please read the whole thing:
I have a table in Lua which is a table of tables something like the below one and I want to remove all the duplicate tables in it.
table1 = {{1, 2, 3}, {1, 2, 3}, {1, 2, 3, 4}}
What I want to do is to remove the duplicate tables and use only one. The result should be like the one below
table2 = {{1, 2, 3}, {1, 2, 3, 4}}
I tried a lot of methods I found online and some of my own and I couldn't get to do it.
Here is what I tried last
local test = {1,2,4,2,3,4,2,3,4,"A", "B", "A"}
local hash = {}
local res = {}
for _,v in ipairs(test) do
if (not hash[v]) then
res[#res+1] = v -- you could print here instead of saving to result table if you wanted
hash[v] = true
end
end
-- Here the test is the input, and res is the output table without
-- any duplicates but this works only for values in it and not for
-- nested tables.
Please help me out.
Let's take pen and paper and think.
What do we have?
A table that contains multiple tables. According to your example those inner tables are sequences. So they only have consecutive integer keys starting from 1. The inner tables' elements are either strings or numbers.
You want to remove duplicate inner tables that is a table that has the same elements as another table before it.
So what do we have to do?
We need to go through our table and check each element and ask if we have seen this inner table's contents before.
So we make a list of sequences that we have seen before.
1) Check if the next element is already on the list.
2) If it is on the list, remove it, else put it on the list.
3) back to 1
Now translate that into Lua
local table1 = {{1, 2, 3}, {1, 2, 3}, {1, 2, 3, 4}}
-- make a list to add what we already have seen
local list = {}
-- make a list of unique items as it is easier than removing items from our input list
local results = {}
-- go over the list and check each element
for i, innerTable in ipairs(table1) do
-- convert it to a string representation so we add it to our list easily
local serialized = table.concat(innerTable, "\x1f")
-- only if it is not on our list yet
if not list[serialized] then
-- add it to the list
table.insert(results, innerTable)
-- add the item to the result list
list[serialized] = true
end
end
-- print the results
for i,v in ipairs(results) do print(v) end
Related
I have this table local cookies = {{["name"]=23, ["value"]=333}, {["name"]=222, ["value"]=33233}} and I want to iterate over the subtables to find the one with the correct "name". Here is what I have tried
for _,elm in ipairs(cookies) do
for k,v in ipairs(elm) do
print(k)
if k == "name" and v == 222 then
print(v)
end
end
end
I does show in the outer for loop that it sees to tables, however, it does not even enter the inner for loop - why? How can I find the subtable for which "name" equals a certain value?
ipairs only iterates over the keys 1, 2, 3, ..., so it won't visit the key "name". If you want to visit all keys, use pairs (though be warned the order of iteration is not predictable).
However, for your example you don't need an inner loop at all. You can simple get the name of elm as elm.name:
for _,elm in ipairs(cookies) do
if elm.name == "222" then
print(elm.name, elm.value)
end
end
In fact, if you don't need the ordering or need to support duplicated cookie names, your cookies table could become a dictionary of name => value, allowing you to write this with no loops:
print(cookies["222"]) --> 33233
guys. Someone can help me with this?
Input
a = {}
a.c = {1,2,3}
print(#a)
print(a.c)
Output
0
table: 0x11ed7a0
Why #a is 0? Why not 1?
Thanks.
It is zero because your table a is not a sequence.
A sequence is a table that uses keys from 1..n where n is the size of the sequence.
In other words, # is used for sequence length, not table length.
From the Lua 5.3 Reference Manual
A table with exactly one border is called a sequence. For instance, the table
{10, 20, 30, 40, 50} is a sequence, as it has only one border (5). The table
{10, 20, 30, nil, 50} has two borders (3 and 5), and therefore it is not a
sequence. The table {nil, 20, 30, nil, nil, 60, nil} has three borders (0, 3,
and 6), so it is not a sequence, too. The table {} is a sequence with border 0.
Note that non-natural keys do not interfere with whether a table is a sequence.
When t is a sequence, #t returns its only border, which corresponds to the
intuitive notion of the length of the sequence. When t is not a sequence, #t
can return any of its borders. (The exact one depends on details of the
internal representation of the table, which in turn can depend on how the table
was populated and the memory addresses of its non-numeric keys.)
Lua tables are a different kind of construct than those in other languages. As the Lua manual reads:
Tables are the main (in fact, the only) data structuring mechanism in Lua, and a powerful one. We use tables to represent ordinary arrays, symbol tables, sets, records, queues, and other data structures, in a simple, uniform, and efficient way.
In addition, a table is dynamic enough that you can use it in multiple ways at once. For example, a table could be used both as an array and a map at the same time. This has some unfortunate consequences internally. Internally, each Lua table has two parts: the array and hash map.
The length operator only operates on the array portion of the table; no extra memory is used to store the total number of items in the table including the hash map portion. If that functionality is desired, it must be manually implemented. A couple good ways to do so would be using getters and setters, manually updating a local counter, or using a proxy table with index and newindex metamethods.
As an interresting side note, it can sometimes become difficult to tell if a value is stored in the array or hash portions of the table. Consider these examples in Lua 5.3:
1: t = {true, nil, true} -- #t = 3
2: t = {true, [2] = true} -- #t = 2
3: t = {true, [3] = true} -- #t = 1
4: t = {true, true, true} t[2] = nil -- #t = 3
I use list comprehension for transforming database rows from the list of tuples to the list of maps. One day I have added some new column into my database table and forget to change the code everywhere.
And because of that I discovered a strange effect: database rows become an empty list.
Example of code in erl console:
> DbRows = [{1, 1, 1}, {2, 2, 2}].
[{1,1,1},{2,2,2}]
> [#{<<"col1">> => Col1, <<"col2">> => Col2} ||{Col1, Col2} <- DbRows].
[]
Why Erlang does not generate exception error: no match of right hand side value in this case?
Is this code OK, or some other syntax is preferred for performing such data transforming?
Erlang does not generate any exception because that's a right syntax. Generator {Col1, Col2} <- DbRows is a filter in the same time. So any element that does not match pattern just skipped.
In your case I would do something like that:
-define(FIELDS, [id, some1, some2]).
DbRows = [{1, 1, 1}, {2, 2, 2}].
Prepare = fun(X) ->
maps:from_list(lists:zip(?FIELDS, tuple_to_list(X)))
end.
[ Prepare(Row) || Row <- DbRows].
And when you add new field you need to add that field in the macros.
I don't like this "feature", since in my experience it tends to mask bugs, but nikit's answer is correct about the reason for the result you see.
You can get the exception by moving the pattern matching to the left side of the list comprehension:
[ case Row of {Col1, Col2} -> #{<<"col1">> => Col1, <<"col2">> => Col2} || Row <- DbRows ]
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)
In Lua, I can add an entry inside table with table.insert(tableName, XYZ). Is there a way I can add already existing table into table? I mean a directly call rather then traversing and add it.
Thanks
The insert in your example will work fine with whatever contents happen to be inside the XYZ variable (number, string, table, function, etc.).
That will not copy the table though it will insert the actual table. If you want to insert a copy of the table then you need to traverse it and insert the contents.
First: In general, you do not need table.insert to put new entries into tables.
A table in Lua is a collection of key-value pairs; entries can be made like this:
local t = {} --the table
local key= "name"
local value = "Charlie"
t[key] = value --make a new entry (replace an existing value at the same key!)
print(t.name) --> "Charlie"
Note that key can have any type (not just integer/string)!
Very often you will need tables for a simple special case of this: A sequence ("list", "array") of values. For Lua, this means you want a table where all the keys are consecutive integers, and contain all non-nil values. The table.insert function is intended for that special case: It allows you to insert a value at a certain position (or to append it at the end of the sequence if no position is specified):
local t = {"a", "b", "d"} --a sequence containing three strings (t[1] = "a", ...)
table.insert(t, "e") --append "e" to the sequence
table.insert(t, 3, "c") --insert "c" at index 3 (moving values at higher indices)
--print the whole sequence
for i=1,#t do
print(t[i])
end
If I understand what you mean correctly, you want to do this:
local t1 = {1, 2, 3}
local t2 = {4, 5, 6}
some_function(t1, t2)
-- t1 is now {1, 2, 3, 4, 5, 6}
There is indeed no way to do this without iterating t2. Here is a way to write some_function:
local some_function = function(t1, t2)
local n = #t1
for i=1,#t2 do t1[n+i] = t2[i] end
end
No, you must copy the second table's key/value pairs into the first table. Copying the existing values from the second table is what's known as a "shallow copy." The first table will reference the same objects as the second table.
This works under limited circumstances:
local n = #t1
for i=1,#t2 do t1[n+i] = t2[i] end
It does attempt to shift the t2 elements to just beyond the existing t1 elements. That could be a vital requirement but wasn't stated in the question.
It has a few of problems, though:
By using #t1 and #t2, it misses keys that aren't positive integers and can miss keys that are integers greater than a skipped integer key (i.e. never assigned or assigned nil).
It accesses the first table with an indexer so could invoke the __newindex metamethod. That probably wouldn't be desirable when only copying is wanted.
It accesses the second table with an indexer so could invoke the __index metamethod. That wouldn't be desirable when only copying is wanted.
You might think that ipairs could be used if only positive integer keys are wanted but it quits on the first nil value found so could miss even more than #t2 does.
Use pairs instead:
for key, value in pairs(t2) do
rawset( t1, key, value )
end
If you do want to avoid replacing existing t1 values when the keys match or otherwise map t2 keys in some way then that has to be defined in the requirements.
Bottom line: pairs is the way to get all the keys. It effectively does a rawget so it avoids invoking __index. rawset is the way to do a copy without invoking __newindex.